# /home/Autopartes/pos/blueprints/whatsapp_bp.py
"""WhatsApp via Baileys Bridge.

Endpoints:
  GET  /pos/api/whatsapp/status    -- Connection status
  GET  /pos/api/whatsapp/qr        -- Get QR code
  POST /pos/api/whatsapp/connect   -- Start connection
  POST /pos/api/whatsapp/logout    -- Disconnect
  POST /pos/api/whatsapp/webhook   -- Receive messages (public)
  POST /pos/api/whatsapp/send      -- Send message
  GET  /pos/api/whatsapp/conversations -- List conversations
"""

from flask import Blueprint, request, jsonify, g
from middleware import require_auth
from tenant_db import get_tenant_conn
from services import whatsapp_service

whatsapp_bp = Blueprint('whatsapp', __name__, url_prefix='/pos/api/whatsapp')


def _enrich_wa_reply_with_part(search_query, vehicle, tenant_conn):
    """Search the refaccionaria's LOCAL inventory and build a WhatsApp reply.

    Returns:
        (formatted_text, first_part_dict) — first_part_dict is used by the
        quotation system to know what to add when the user says "cotizar".
        first_part_dict has: inventory_id, part_number, name, brand, price, tax_rate
    """
    if not tenant_conn:
        return None, None

    try:
        # Translate common English search terms to Spanish for local inventory
        # (the AI sends search_query in English, but local inventory names
        # are often in Spanish)
        from services.translations import PART_TRANSLATIONS
        search_terms = [search_query]
        # Add the Spanish translation if we have one
        for en, es in PART_TRANSLATIONS.items():
            if en.upper() in search_query.upper():
                search_terms.append(es)
                break

        # Build ILIKE conditions for all search terms
        conditions = []
        params = []
        for term in search_terms:
            conditions.append("(i.name ILIKE %s OR i.part_number ILIKE %s OR i.brand ILIKE %s)")
            like = f'%{term}%'
            params.extend([like, like, like])

        where_search = ' OR '.join(conditions)

        cur = tenant_conn.cursor()
        cur.execute(f"""
            SELECT i.part_number, i.name, i.brand, i.price_1, i.price_2, i.price_3,
                   COALESCE(s.stock, 0) AS stock,
                   i.unit, i.location
            FROM inventory i
            LEFT JOIN (
                SELECT inventory_id, SUM(quantity) AS stock
                FROM inventory_operations
                GROUP BY inventory_id
            ) s ON s.inventory_id = i.id
            WHERE i.is_active = TRUE
              AND ({where_search})
            ORDER BY
                COALESCE(s.stock, 0) > 0 DESC,
                i.name
            LIMIT 10
        """, params)

        rows = cur.fetchall()
        cur.close()

        if not rows:
            return ('❌ No tenemos esa parte en inventario actualmente.\n'
                    '_Puedes preguntar por otra parte o visitarnos en tienda._'), None

        # Split into in-stock and out-of-stock
        in_stock = [r for r in rows if r[6] > 0]
        out_stock = [r for r in rows if r[6] <= 0]

        # Build the first-part dict for quotation tracking
        # Use the first in-stock part, or first out-of-stock if none available
        best = in_stock[0] if in_stock else (out_stock[0] if out_stock else None)
        first_part = None
        if best:
            first_part = {
                'inventory_id': None,  # we'd need the id — fetch it
                'part_number': best[0],
                'name': best[1],
                'brand': best[2] or '',
                'price': float(best[3]) if best[3] else 0,
                'tax_rate': 0.16,
                'stock': best[6],
                'unit': best[7] or 'PZA',
            }
            # Fetch the inventory ID for the quotation item FK
            try:
                cur2 = tenant_conn.cursor()
                cur2.execute("SELECT id FROM inventory WHERE part_number = %s AND is_active = TRUE LIMIT 1",
                             (best[0],))
                inv_row = cur2.fetchone()
                if inv_row:
                    first_part['inventory_id'] = inv_row[0]
                cur2.close()
            except Exception:
                pass

        lines = []

        if in_stock:
            lines.append('✅ *Tenemos en stock:*')
            lines.append('')
            for r in in_stock:
                part_num, name, brand, p1, p2, p3, stock, unit, location = r
                brand_str = f'*{brand}*' if brand else ''
                price_str = f'${float(p1):,.2f}' if p1 else 'Consultar precio'
                lines.append(f'  • {brand_str} {name}')
                lines.append(f'    #{part_num} — {price_str} ({stock} {unit or "pzas"} disponibles)')
                lines.append('')
        else:
            lines.append('⚠️ *Tenemos estas opciones pero sin stock actualmente:*')
            lines.append('')
            for r in out_stock[:5]:
                part_num, name, brand, p1, p2, p3, stock, unit, location = r
                brand_str = f'*{brand}*' if brand else ''
                price_str = f'${float(p1):,.2f}' if p1 else ''
                lines.append(f'  • {brand_str} {name} #{part_num} {price_str}')
            lines.append('')
            lines.append('_Podemos pedirlo — consulta tiempo de entrega._')

        # Vehicle context
        if vehicle and vehicle.get('brand'):
            v_str = f"{vehicle.get('brand','')} {vehicle.get('model','')} {vehicle.get('year','')}"
            lines.append(f'🚗 Vehículo: {v_str.strip()}')

        lines.append('\n📞 _Escribe "cotizar" para agregar a tu cotización._')

        return '\n'.join(lines), first_part

    except Exception as e:
        print(f"[WA-AI] Enrichment error: {e}")
        return None, None


@whatsapp_bp.route('/status', methods=['GET'])
@require_auth()
def status():
    return jsonify(whatsapp_service.get_status())


@whatsapp_bp.route('/qr', methods=['GET'])
@require_auth()
def qr():
    return jsonify(whatsapp_service.get_qr())


@whatsapp_bp.route('/connect', methods=['POST'])
@require_auth()
def connect():
    return jsonify(whatsapp_service.connect())


@whatsapp_bp.route('/logout', methods=['POST'])
@require_auth()
def logout():
    return jsonify(whatsapp_service.logout())


@whatsapp_bp.route('/webhook', methods=['POST'])
def webhook():
    """Receive messages from Baileys bridge (public, no auth).

    Flow:
      1. Persist the incoming message to the tenant's whatsapp_messages log.
      2. Build inventory context for the AI (what this tenant has in stock).
      3. Ask the chatbot for a reply, enriched with that context.
      4. Send the reply back via the Baileys bridge.
    """
    data = request.get_json(force=True, silent=True) or {}

    if data.get('event') != 'messages.upsert':
        return jsonify({'ok': True})

    msg = whatsapp_service.process_incoming(data)
    if not msg.get('phone') or msg.get('from_me'):
        return jsonify({'ok': True})

    # Reuse one tenant connection for the whole webhook path — we need it
    # for persistence AND for the inventory-context lookup.
    # TODO: resolve tenant from phone number when multi-tenant WhatsApp arrives.
    tenant_id = 11
    tenant_conn = None
    inventory_context = None
    try:
        tenant_conn = get_tenant_conn(tenant_id)

        # 1. Log the incoming message (with contact display name)
        cur = tenant_conn.cursor()
        cur.execute("""
            INSERT INTO whatsapp_messages (phone, direction, message_text, wa_message_id, push_name)
            VALUES (%s, 'incoming', %s, %s, %s)
            ON CONFLICT DO NOTHING
        """, (msg['phone'], msg['text'], msg['message_id'], msg.get('push_name') or None))
        tenant_conn.commit()
        cur.close()

        # 2. Build inventory context once per webhook call so the chatbot
        # can say things like "tengo 5 Bosch BP-123 por $450".
        try:
            from services.ai_chat import get_inventory_context
            inventory_context = get_inventory_context(tenant_conn)
        except Exception as e:
            print(f"[WA-AI] inventory_context failed: {e}")
            inventory_context = None
    except Exception as e:
        print(f"[WA-AI] tenant connection failed: {e}")

    # 3. Dispatch by media kind + quotation commands
    reply = None
    reply_to = msg.get('jid') or msg['phone']
    media_kind = msg.get('media_kind', 'text')
    clean_phone = msg.get('phone', '')

    # ── Check for quotation commands FIRST (before AI) ──
    if media_kind == 'text' and msg.get('text'):
        from services.wa_quotation import (
            detect_quote_intent, get_open_quotation, create_quotation,
            add_item_to_quotation, get_quotation_detail, format_quotation_wa,
            clear_quotation, confirm_quotation, get_last_shown_part, set_last_shown_part,
        )
        has_open = bool(tenant_conn and get_open_quotation(tenant_conn, clean_phone))
        intent, qty = detect_quote_intent(msg['text'], has_open_quote=has_open)

        if intent == 'add':
            last_part = get_last_shown_part(clean_phone)
            if not last_part:
                reply = '⚠️ Primero pregunta por una parte y luego escribe "cotizar" para agregarla.'
            elif tenant_conn:
                qid = get_open_quotation(tenant_conn, clean_phone)
                if not qid:
                    qid = create_quotation(tenant_conn, clean_phone)
                add_item_to_quotation(tenant_conn, qid, last_part, quantity=qty or 1)
                detail = get_quotation_detail(tenant_conn, qid)
                item_count = len(detail['items']) if detail else 0
                reply = (
                    f'✅ *{last_part.get("name", "")}* × {qty or 1} agregado a tu cotización.\n'
                    f'Llevas {item_count} producto{"s" if item_count != 1 else ""} — total parcial: ${detail["total"]:,.2f}\n\n'
                    f'_Sigue preguntando por más partes, o escribe "enviar cotización" cuando termines._'
                )

        elif intent == 'send':
            if tenant_conn:
                qid = get_open_quotation(tenant_conn, clean_phone)
                if qid:
                    detail = get_quotation_detail(tenant_conn, qid)
                    reply = format_quotation_wa(detail)
                    if not reply:
                        reply = '⚠️ Tu cotización está vacía. Pregunta por partes y escribe "cotizar" para agregarlas.'
                else:
                    reply = '⚠️ No tienes una cotización abierta. Pregunta por una parte primero.'

        elif intent == 'clear':
            if tenant_conn:
                clear_quotation(tenant_conn, clean_phone)
            reply = '🗑️ Cotización limpiada. Pregunta por partes para empezar una nueva.'

        elif intent == 'confirm':
            if tenant_conn:
                qid = confirm_quotation(tenant_conn, clean_phone)
                if qid:
                    reply = (
                        f'✅ *Pedido confirmado!*\n\n'
                        f'Tu cotización #{qid} fue registrada.\n'
                        f'Nos pondremos en contacto contigo para coordinar la entrega/recolección.\n\n'
                        f'¡Gracias por tu compra! 🙏'
                    )
                else:
                    reply = '⚠️ No tienes una cotización abierta para confirmar.'

        if intent is not None:
            # It was a quote command — send reply and skip the AI
            if reply:
                result = whatsapp_service.send_message(reply_to, reply)
                if tenant_conn:
                    try:
                        cur_save = tenant_conn.cursor()
                        cur_save.execute("INSERT INTO whatsapp_messages (phone, direction, message_text) VALUES (%s, 'outgoing', %s)", (clean_phone, reply))
                        tenant_conn.commit()
                        cur_save.close()
                    except Exception:
                        pass
            # Clean up and return early
            if tenant_conn:
                try: tenant_conn.close()
                except Exception: pass
            return jsonify({'ok': True})

    try:
        if media_kind == 'image' and msg.get('media_base64'):
            from services.ai_chat import chat_with_image
            # Prompt: use the caption if provided, else default to
            # "identify this part" which chat_with_image handles gracefully.
            prompt = msg.get('text') or 'Identifica esta parte automotriz y sugiere terminos de busqueda.'
            ai_resp = chat_with_image(
                user_message=prompt,
                image_base64=msg['media_base64'],
                inventory_context=inventory_context,
            )
            reply = ai_resp.get('message', '') or ''
            print(f"[WA-AI] Image from {reply_to}: {reply[:80]}...")

        elif media_kind == 'audio' and msg.get('media_base64'):
            # Voice note handling — transcribe first, then chat().
            # See services.whisper_local for the transcriber.
            try:
                from services.whisper_local import transcribe_audio_base64
                transcript = transcribe_audio_base64(
                    msg['media_base64'],
                    mimetype=msg.get('media_mimetype') or 'audio/ogg',
                )
            except ImportError:
                transcript = None
                print("[WA-AI] whisper_local not installed — voice notes skipped")
            except Exception as e:
                transcript = None
                print(f"[WA-AI] Whisper transcription failed: {e}")

            if transcript:
                print(f"[WA-AI] Voice note transcribed: {transcript[:100]}")
                from services.ai_chat import chat
                ai_resp = chat(transcript, inventory_context=inventory_context)
                reply = ai_resp.get('message', '') or ''
                # Prefix the reply so the sender knows we understood the voice note
                if reply:
                    reply = f'🎙️ Entendi: "{transcript}"\n\n{reply}'
            else:
                reply = ('Recibi tu nota de voz pero no pude transcribirla. '
                         'Puedes escribirme el mensaje?')

        elif msg.get('text'):
            # Plain text message — standard chatbot flow
            from services.ai_chat import chat
            ai_resp = chat(msg['text'], inventory_context=inventory_context)
            reply = ai_resp.get('message', '') or ''

            # Enrich: if the AI returned a search_query, look up real parts
            # from the catalog and append them to the WhatsApp reply.
            search_q = ai_resp.get('search_query')
            vehicle = ai_resp.get('vehicle')
            if search_q and reply:
                try:
                    enrichment, found_part = _enrich_wa_reply_with_part(search_q, vehicle, tenant_conn)
                    if enrichment:
                        reply = reply + '\n\n' + enrichment
                    # Track the found part so "cotizar" can add it
                    if found_part:
                        from services.wa_quotation import set_last_shown_part
                        set_last_shown_part(clean_phone, found_part)
                except Exception as enrich_err:
                    print(f"[WA-AI] Enrichment failed: {enrich_err}")

        # Send reply if we produced one
        if reply:
            result = whatsapp_service.send_message(reply_to, reply)
            print(f"[WA-AI] Replied to {reply_to} ({media_kind}): {reply[:80]}... result={result}")

            # Save the bot's reply to DB so it shows in the WhatsApp UI
            if tenant_conn:
                try:
                    cur2 = tenant_conn.cursor()
                    cur2.execute("""
                        INSERT INTO whatsapp_messages (phone, direction, message_text)
                        VALUES (%s, 'outgoing', %s)
                    """, (msg['phone'], reply))
                    tenant_conn.commit()
                    cur2.close()
                except Exception as db_err:
                    print(f"[WA-AI] Failed to save bot reply to DB: {db_err}")

    except Exception as e:
        print(f"[WA-AI] Error handling {media_kind} from {reply_to}: {e}")

    # 4. Clean up the connection
    if tenant_conn is not None:
        try:
            tenant_conn.close()
        except Exception:
            pass

    return jsonify({'ok': True})


@whatsapp_bp.route('/send', methods=['POST'])
@require_auth()
def send():
    data = request.get_json() or {}
    phone = data.get('phone', '')
    message = data.get('message', '')
    if not phone or not message:
        return jsonify({'error': 'phone and message required'}), 400

    result = whatsapp_service.send_message(phone, message)

    # Save outgoing message
    try:
        conn = get_tenant_conn(g.tenant_id)
        cur = conn.cursor()
        cur.execute("""
            INSERT INTO whatsapp_messages (phone, direction, message_text)
            VALUES (%s, 'outgoing', %s)
        """, (phone, message))
        conn.commit()
        cur.close()
        conn.close()
    except Exception:
        pass

    return jsonify(result)


@whatsapp_bp.route('/conversations', methods=['GET'])
@require_auth()
def conversations():
    try:
        conn = get_tenant_conn(g.tenant_id)
        cur = conn.cursor()
        # Clean up phone format: strip @lid and @s.whatsapp.net suffixes
        # so all variants of the same number are grouped together.
        cur.execute("""
            WITH cleaned AS (
                SELECT
                    REPLACE(REPLACE(phone, '@s.whatsapp.net', ''), '@lid', '') AS clean_phone,
                    message_text,
                    direction,
                    created_at,
                    push_name
                FROM whatsapp_messages
            )
            SELECT clean_phone,
                   (ARRAY_AGG(message_text ORDER BY created_at DESC))[1] AS last_message,
                   (ARRAY_AGG(direction ORDER BY created_at DESC))[1] AS last_direction,
                   MAX(created_at) AS last_at,
                   COUNT(*) AS msg_count,
                   (ARRAY_AGG(push_name ORDER BY created_at DESC) FILTER (WHERE push_name IS NOT NULL AND push_name != ''))[1] AS contact_name
            FROM cleaned
            GROUP BY clean_phone
            ORDER BY MAX(created_at) DESC
            LIMIT 50
        """)
        convos = [{
            'phone': r[0],
            'last_message': r[1] or '',
            'last_direction': r[2] or 'incoming',
            'last_at': str(r[3]),
            'count': r[4],
            'contact_name': r[5] or '',
        } for r in cur.fetchall()]
        cur.close()
        conn.close()
        return jsonify({'conversations': convos})
    except Exception as e:
        return jsonify({'conversations': [], 'error': str(e)})


@whatsapp_bp.route('/conversations/<path:phone>', methods=['GET'])
@require_auth()
def conversation_messages(phone):
    # Strip @lid or @s.whatsapp.net suffix for DB lookup
    clean_phone = phone.replace('@s.whatsapp.net', '').replace('@lid', '')
    try:
        conn = get_tenant_conn(g.tenant_id)
        cur = conn.cursor()
        # Match all variants of this phone number
        cur.execute("""
            SELECT id, direction, message_text, created_at
            FROM whatsapp_messages
            WHERE REPLACE(REPLACE(phone, '@s.whatsapp.net', ''), '@lid', '') = %s
            ORDER BY created_at
            LIMIT 100
        """, (clean_phone,))
        msgs = [{
            'id': r[0],
            'direction': r[1],
            'message_text': r[2] or '',
            'created_at': str(r[3]),
        } for r in cur.fetchall()]
        cur.close()
        conn.close()
        return jsonify({'messages': msgs})
    except Exception as e:
        return jsonify({'messages': [], 'error': str(e)})


@whatsapp_bp.route('/conversations/<path:phone>', methods=['DELETE'])
@require_auth()
def delete_conversation(phone):
    """Delete all messages for a phone number."""
    clean_phone = phone.replace('@s.whatsapp.net', '').replace('@lid', '')
    try:
        conn = get_tenant_conn(g.tenant_id)
        cur = conn.cursor()
        cur.execute("""
            DELETE FROM whatsapp_messages
            WHERE REPLACE(REPLACE(phone, '@s.whatsapp.net', ''), '@lid', '') = %s
        """, (clean_phone,))
        deleted = cur.rowcount
        conn.commit()
        cur.close()
        conn.close()
        return jsonify({'ok': True, 'deleted': deleted})
    except Exception as e:
        return jsonify({'error': str(e)}), 500


@whatsapp_bp.route('/conversations', methods=['DELETE'])
@require_auth()
def delete_all_conversations():
    """Delete ALL whatsapp messages."""
    try:
        conn = get_tenant_conn(g.tenant_id)
        cur = conn.cursor()
        cur.execute("DELETE FROM whatsapp_messages")
        deleted = cur.rowcount
        conn.commit()
        cur.close()
        conn.close()
        return jsonify({'ok': True, 'deleted': deleted})
    except Exception as e:
        return jsonify({'error': str(e)}), 500
