"""
WhatsApp Quotation Service — conversational quote builder.

Tracks per-phone "open quotations" so a customer can ask about multiple
parts over several messages and receive a single formatted quotation at
the end.

Flow:
  1. Customer asks about a part → bot shows local inventory match
  2. Customer says "cotizar" / "agregar" → last-shown part added to quote
  3. Repeat for more parts
  4. Customer says "enviar cotización" / "listo" → formatted quote sent
  5. Customer says "limpiar" / "nueva cotización" → quote cleared

The quotation is stored in the tenant's existing `quotations` +
`quotation_items` tables so it also appears in the POS quotation list.
"""

import re
from datetime import date, timedelta


# ─── Intent detection ────────────────────────────────────────────────

# Commands the customer can type (case-insensitive, accent-insensitive)
# NOTE: "si" is NOT here — it's handled as 'confirm' to avoid ambiguity
# with "si" after a quotation was sent (which means "confirm order").
_ADD_PATTERNS = re.compile(
    r'^(cotizar|agregar|agregalo|agrega|añadir|quiero ese|ese mero|'
    r'dame ese|lo quiero|me lo apartas|si.?cotiza)$',
    re.IGNORECASE
)

_SEND_PATTERNS = re.compile(
    r'^(enviar cotizaci[oó]n|listo|enviar|mandar cotizaci[oó]n|ya es todo|'
    r'eso es todo|mandame la cotizaci[oó]n|terminé|termine|ver cotizaci[oó]n|'
    r'mi cotizaci[oó]n|total|cuanto es)$',
    re.IGNORECASE
)

_CLEAR_PATTERNS = re.compile(
    r'^(limpiar|nueva cotizaci[oó]n|borrar cotizaci[oó]n|empezar de nuevo|cancelar cotizaci[oó]n)$',
    re.IGNORECASE
)

# "si", "va", "confirmo" — confirm the quotation (close it as accepted)
_CONFIRM_PATTERNS = re.compile(
    r'^(si|sí|va|confirmo|confirmar|acepto|de acuerdo|ok|okay|dale)$',
    re.IGNORECASE
)

_QTY_PATTERN = re.compile(
    r'^(cotizar|agregar|dame|quiero)\s+(\d+)$',
    re.IGNORECASE
)


def detect_quote_intent(text, has_open_quote=False):
    """Detect if the message is a quotation command.

    Args:
        text: the user's message
        has_open_quote: True if this phone has an active quotation

    Returns:
        ('add', quantity) — add last part to quote
        ('send', None)    — send the full quotation
        ('clear', None)   — clear the quotation
        ('confirm', None) — confirm/accept the quotation
        (None, None)      — not a quote command, pass to AI
    """
    if not text:
        return None, None

    t = text.strip()

    # Check for quantity: "cotizar 3", "agregar 5"
    qty_match = _QTY_PATTERN.match(t)
    if qty_match:
        return 'add', int(qty_match.group(2))

    if _ADD_PATTERNS.match(t):
        return 'add', 1

    if _SEND_PATTERNS.match(t):
        return 'send', None

    if _CLEAR_PATTERNS.match(t):
        return 'clear', None

    # "si" / "va" / "confirmo" — only counts as 'confirm' when there's
    # an open quote. Otherwise pass to the AI as normal conversation.
    if has_open_quote and _CONFIRM_PATTERNS.match(t):
        return 'confirm', None

    return None, None


def confirm_quotation(tenant_conn, phone):
    """Mark the open quotation as confirmed/accepted."""
    qid = get_open_quotation(tenant_conn, phone)
    if not qid:
        return None
    cur = tenant_conn.cursor()
    cur.execute("UPDATE quotations SET status = 'converted' WHERE id = %s", (qid,))
    tenant_conn.commit()
    cur.close()
    clear_last_shown(tenant_conn, phone)
    return qid


# ─── Persistent last-shown-part per phone ────────────────────────────
# Tracks what part the bot last showed so "cotizar" knows what to add.
# Stored in tenant DB table whatsapp_sessions so it survives restarts.

_WHATSAPP_SESSIONS_SQL = """
CREATE TABLE IF NOT EXISTS whatsapp_sessions (
    phone VARCHAR(50) PRIMARY KEY,
    last_shown JSONB,
    vehicle JSONB,
    updated_at TIMESTAMP DEFAULT NOW()
);
"""


def _ensure_sessions_table(tenant_conn):
    cur = tenant_conn.cursor()
    cur.execute(_WHATSAPP_SESSIONS_SQL)
    # Migrate: add vehicle column if table already existed without it
    cur.execute("""
        ALTER TABLE whatsapp_sessions
        ADD COLUMN IF NOT EXISTS vehicle JSONB
    """)
    tenant_conn.commit()
    cur.close()


def set_last_shown_part(tenant_conn, phone, part_info):
    """Store the last part shown to this phone number.

    part_info: dict with keys inventory_id, part_number, name, brand,
    price, stock, unit
    """
    try:
        _ensure_sessions_table(tenant_conn)
        cur = tenant_conn.cursor()
        import json
        cur.execute("""
            INSERT INTO whatsapp_sessions (phone, last_shown, updated_at)
            VALUES (%s, %s, NOW())
            ON CONFLICT (phone) DO UPDATE SET last_shown = EXCLUDED.last_shown, updated_at = NOW()
        """, (phone, json.dumps(part_info)))
        tenant_conn.commit()
        cur.close()
    except Exception as e:
        print(f"[WA-SESSION] Failed to persist last_shown for {phone}: {e}")


def get_last_shown_part(tenant_conn, phone):
    try:
        _ensure_sessions_table(tenant_conn)
        cur = tenant_conn.cursor()
        cur.execute("SELECT last_shown FROM whatsapp_sessions WHERE phone = %s", (phone,))
        row = cur.fetchone()
        cur.close()
        if row and row[0]:
            return row[0]
    except Exception as e:
        print(f"[WA-SESSION] Failed to read last_shown for {phone}: {e}")
    return None


def clear_last_shown(tenant_conn, phone):
    try:
        _ensure_sessions_table(tenant_conn)
        cur = tenant_conn.cursor()
        cur.execute("DELETE FROM whatsapp_sessions WHERE phone = %s", (phone,))
        tenant_conn.commit()
        cur.close()
    except Exception as e:
        print(f"[WA-SESSION] Failed to clear last_shown for {phone}: {e}")


def set_vehicle(tenant_conn, phone, vehicle):
    """Store the detected vehicle for this phone number.

    vehicle: dict with keys brand, model, year
    """
    try:
        _ensure_sessions_table(tenant_conn)
        cur = tenant_conn.cursor()
        import json
        cur.execute("""
            INSERT INTO whatsapp_sessions (phone, vehicle, updated_at)
            VALUES (%s, %s, NOW())
            ON CONFLICT (phone) DO UPDATE SET vehicle = EXCLUDED.vehicle, updated_at = NOW()
        """, (phone, json.dumps(vehicle)))
        tenant_conn.commit()
        cur.close()
    except Exception as e:
        print(f"[WA-SESSION] Failed to persist vehicle for {phone}: {e}")


def get_vehicle(tenant_conn, phone):
    """Retrieve the stored vehicle for this phone number."""
    try:
        _ensure_sessions_table(tenant_conn)
        cur = tenant_conn.cursor()
        cur.execute("SELECT vehicle FROM whatsapp_sessions WHERE phone = %s", (phone,))
        row = cur.fetchone()
        cur.close()
        if row and row[0]:
            return row[0]
    except Exception as e:
        print(f"[WA-SESSION] Failed to read vehicle for {phone}: {e}")
    return None


def clear_session(tenant_conn, phone):
    """Clear all session data (last_shown + vehicle) for this phone."""
    try:
        _ensure_sessions_table(tenant_conn)
        cur = tenant_conn.cursor()
        cur.execute("DELETE FROM whatsapp_sessions WHERE phone = %s", (phone,))
        tenant_conn.commit()
        cur.close()
    except Exception as e:
        print(f"[WA-SESSION] Failed to clear session for {phone}: {e}")


# ─── Quotation CRUD ─────────────────────────────────────────────────

def get_open_quotation(tenant_conn, phone):
    """Find an active quotation for this phone, or None."""
    cur = tenant_conn.cursor()
    cur.execute("""
        SELECT id FROM quotations
        WHERE notes LIKE %s AND status = 'active'
        ORDER BY created_at DESC LIMIT 1
    """, (f'%WA:{phone}%',))
    row = cur.fetchone()
    cur.close()
    return row[0] if row else None


def create_quotation(tenant_conn, phone):
    """Create a new quotation tagged with this phone number."""
    cur = tenant_conn.cursor()
    cur.execute("""
        INSERT INTO quotations (subtotal, tax_total, total, status, notes, valid_until)
        VALUES (0, 0, 0, 'active', %s, %s)
        RETURNING id
    """, (f'WA:{phone}', date.today() + timedelta(days=7)))
    qid = cur.fetchone()[0]
    tenant_conn.commit()
    cur.close()
    return qid


def add_item_to_quotation(tenant_conn, quote_id, part_info, quantity=1):
    """Add a part to an existing quotation and recalculate totals."""
    price = float(part_info.get('price') or 0)
    tax_rate = float(part_info.get('tax_rate') or 0.16)
    subtotal = round(price * quantity, 2)

    cur = tenant_conn.cursor()
    cur.execute("""
        INSERT INTO quotation_items
            (quotation_id, inventory_id, part_number, name, quantity, unit_price, tax_rate, subtotal)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
    """, (
        quote_id,
        part_info.get('inventory_id'),
        part_info.get('part_number', ''),
        part_info.get('name', ''),
        quantity,
        price,
        tax_rate,
        subtotal,
    ))

    # Recalculate totals
    cur.execute("""
        SELECT COALESCE(SUM(subtotal), 0),
               COALESCE(SUM(subtotal * tax_rate), 0)
        FROM quotation_items WHERE quotation_id = %s
    """, (quote_id,))
    sub, tax = cur.fetchone()
    cur.execute("""
        UPDATE quotations SET subtotal = %s, tax_total = %s, total = %s
        WHERE id = %s
    """, (sub, tax, round(sub + tax, 2), quote_id))

    tenant_conn.commit()
    cur.close()
    return subtotal


def get_quotation_detail(tenant_conn, quote_id):
    """Return full quotation with items."""
    cur = tenant_conn.cursor()
    cur.execute("""
        SELECT id, subtotal, tax_total, total, status, valid_until, created_at
        FROM quotations WHERE id = %s
    """, (quote_id,))
    q = cur.fetchone()
    if not q:
        cur.close()
        return None

    cur.execute("""
        SELECT part_number, name, quantity, unit_price, tax_rate, subtotal
        FROM quotation_items WHERE quotation_id = %s ORDER BY id
    """, (quote_id,))
    items = cur.fetchall()
    cur.close()

    return {
        'id': q[0],
        'subtotal': float(q[1]),
        'tax_total': float(q[2]),
        'total': float(q[3]),
        'status': q[4],
        'valid_until': str(q[5]) if q[5] else None,
        'created_at': str(q[6]) if q[6] else None,
        'items': [{
            'part_number': it[0],
            'name': it[1],
            'quantity': it[2],
            'unit_price': float(it[3]),
            'tax_rate': float(it[4]),
            'subtotal': float(it[5]),
        } for it in items],
    }


def clear_quotation(tenant_conn, phone):
    """Cancel the open quotation for this phone."""
    qid = get_open_quotation(tenant_conn, phone)
    if qid:
        cur = tenant_conn.cursor()
        cur.execute("UPDATE quotations SET status = 'cancelled' WHERE id = %s", (qid,))
        tenant_conn.commit()
        cur.close()
    clear_last_shown(tenant_conn, phone)
    return qid


# ─── Format quotation for WhatsApp ──────────────────────────────────

def format_quotation_wa(detail):
    """Format a quotation as a WhatsApp-friendly text message."""
    if not detail or not detail.get('items'):
        return None

    lines = [
        f'📄 *COTIZACIÓN #{detail["id"]}*',
        f'Fecha: {detail["created_at"][:10] if detail.get("created_at") else "hoy"}',
        f'Vigencia: {detail.get("valid_until") or "7 días"}',
        '',
        '─────────────────────',
    ]

    for i, item in enumerate(detail['items'], 1):
        qty = item['quantity']
        price = item['unit_price']
        sub = item['subtotal']
        lines.append(f'{i}. {item["name"]}')
        lines.append(f'   #{item["part_number"]} × {qty} = ${sub:,.2f}')

    lines.append('─────────────────────')
    lines.append(f'   Subtotal: ${detail["subtotal"]:,.2f}')
    lines.append(f'   IVA:      ${detail["tax_total"]:,.2f}')
    lines.append(f'   *TOTAL:   ${detail["total"]:,.2f}*')
    lines.append('')
    lines.append('_Responde "si" para confirmar el pedido._')
    lines.append('_Responde "limpiar" para empezar de nuevo._')

    return '\n'.join(lines)
