<?php
if (count(get_included_files()) === 1) {
    http_response_code(403);
    exit('Forbidden');
}

require_once dirname(__DIR__) . '/services/agent_service.php';
require_once dirname(__DIR__) . '/services/meta_whatsapp.php';
require_once dirname(__DIR__) . '/services/token_crypto.php';
require_once dirname(__DIR__) . '/services/platform_whatsapp.php';

$method = $_SERVER['REQUEST_METHOD'];

// ── GET: Meta verifica el webhook al configurarlo en el panel ─────────────────
if ($method === 'GET') {
    $mode      = $_GET['hub_mode']         ?? '';
    $token     = $_GET['hub_verify_token'] ?? '';
    $challenge = $_GET['hub_challenge']    ?? '';

    $expectedToken = getenv('META_WEBHOOK_VERIFY_TOKEN') ?: '';

    if ($mode === 'subscribe' && $expectedToken !== '' && $token === $expectedToken) {
        http_response_code(200);
        echo $challenge;
    } else {
        http_response_code(403);
        echo 'Forbidden';
    }
    exit;
}

if ($method !== 'POST') {
    http_response_code(405);
    exit;
}

$rawBody = file_get_contents('php://input');

if (!MetaWhatsApp::validateSignature($rawBody)) {
    http_response_code(403);
    echo 'Invalid signature';
    exit;
}

$payload = json_decode($rawBody, true);

if (($payload['object'] ?? '') !== 'whatsapp_business_account') {
    http_response_code(200);
    echo 'ok';
    exit;
}

$db = DB::connect();

// ── Fase 1: parsear payload y armar lista de trabajos pendientes ──────────────
// Hacemos TODA la lógica de resolución primero, respondemos 200 al final,
// y luego ejecutamos los envíos — así fastcgi_finish_request() aplica a todo.

$pendingText  = []; // mensajes de texto para procesar con el agente
$pendingMedia = []; // mensajes de media: enviar fallback directamente

foreach ($payload['entry'] ?? [] as $entry) {
    foreach ($entry['changes'] ?? [] as $change) {
        if (($change['field'] ?? '') !== 'messages') {
            continue;
        }
        $value = $change['value'] ?? [];

        if (empty($value['messages'])) {
            continue;
        }

        $phoneNumberId = $value['metadata']['phone_number_id'] ?? '';
        $message       = $value['messages'][0];
        $msgId         = (string)($message['id'] ?? '');
        $msgType       = (string)($message['type'] ?? '');
        $customerWaId  = (string)($message['from'] ?? '');
        $profileName   = (string)($value['contacts'][0]['profile']['name'] ?? 'Cliente');

        if ($customerWaId === '' || $phoneNumberId === '') {
            continue;
        }

        // Eventos del sistema y reacciones → ignorar silenciosamente SIN consultar DB
        if (in_array($msgType, ['reaction', 'system', 'unsupported'], true)) {
            continue;
        }

        // ── Capa A: mensaje al número de Supraide (dueño escribe a la plataforma) ─
        // El dueño escribe al número de Supraide → respuesta de soporte, sin Gemini.
        $supraidePid = PlatformWhatsApp::phoneNumberId();
        if ($supraidePid !== '' && $phoneNumberId === $supraidePid) {
            if ($msgType === 'text') {
                $body = trim((string)($message['text']['body'] ?? ''));
                if ($body !== '') {
                    // Intentar identificar al dueño por su teléfono
                    $ownerName = '';
                    try {
                        $ownerRow = $db->prepare(
                            "SELECT u.name FROM users u WHERE u.phone = :p AND u.role = 'owner' LIMIT 1"
                        );
                        $ownerRow->execute([':p' => $customerWaId]);
                        $ownerName = (string)($ownerRow->fetchColumn() ?: '');
                    } catch (Throwable $_e) {}
                    $pendingMedia[] = [
                        'phoneNumberId' => $supraidePid,
                        'customerWaId'  => $customerWaId,
                        'fallback'      => PlatformWhatsApp::buildSoporteReply($ownerName),
                        'accessToken'   => getenv('SUPRAIDE_ACCESS_TOKEN') ?: '',
                    ];
                }
            }
            continue; // no procesar como mensaje de tenant
        }

        // ── Resolver tenant y credenciales ─────────────────────────────────────
        $stmt = $db->prepare(
            "SELECT tw.access_token, tw.waba_id, t.*
             FROM tenant_whatsapp tw
             JOIN tenants t ON t.id = tw.tenant_id
             WHERE tw.phone_number_id = :pid AND tw.status = 'active' AND t.deleted_at IS NULL
             LIMIT 1"
        );
        $stmt->execute([':pid' => $phoneNumberId]);
        $row = $stmt->fetch();

        if (!$row) {
            error_log("Meta webhook: tenant no encontrado para phone_number_id=$phoneNumberId");
            $db->prepare(
                "INSERT INTO agent_logs (type, gemini_call, payload) VALUES ('meta_unmapped', 0, :p)"
            )->execute([':p' => json_encode(['phone_number_id' => $phoneNumberId, 'from' => $customerWaId])]);
            continue;
        }

        // Descifrar token
        try {
            $accessToken = TokenCrypto::decrypt((string)$row['access_token']);
        } catch (Throwable $e) {
            error_log("Meta webhook: descifrado de token fallido para phone_number_id=$phoneNumberId — " . $e->getMessage());
            $db->prepare(
                "INSERT INTO agent_logs (type, gemini_call, payload) VALUES ('meta_token_error', 0, :p)"
            )->execute([':p' => json_encode(['phone_number_id' => $phoneNumberId, 'error' => $e->getMessage()])]);
            continue;
        }

        // ── Mensajes interactivos: extraer el texto del botón/lista elegido ────────
        // Cuando el usuario toca un botón de WhatsApp, llega como type='interactive'.
        // Extraemos el título y lo procesamos como si fuera un mensaje de texto normal.
        $interactiveBody = null;
        if ($msgType === 'interactive') {
            $ia = $message['interactive'] ?? [];
            $interactiveBody = match ($ia['type'] ?? '') {
                'button_reply' => trim($ia['button_reply']['title'] ?? ''),
                'list_reply'   => trim($ia['list_reply']['title'] ?? ''),
                default        => null,
            };
            if ($interactiveBody !== null && $interactiveBody !== '') {
                $msgType = 'text'; // tratar como texto
            } else {
                continue; // tipo interactive desconocido, ignorar
            }
        }

        // ── Bug 1 fix: media → respuesta de fallback amable, sin invocar Gemini ─
        // image, audio, video, document, sticker → cliente intentó compartir algo
        if ($msgType !== 'text') {
            $locale   = $row['locale'] ?? 'es';
            $fallback = ($locale === 'en')
                ? 'Hi! I can only read text messages for now. Please write your question and I\'ll be happy to help.'
                : '¡Hola! Por ahora solo puedo leer mensajes de texto. Escribí tu consulta y te ayudo con gusto.';
            $pendingMedia[] = [
                'phoneNumberId' => $phoneNumberId,
                'customerWaId'  => $customerWaId,
                'fallback'      => $fallback,
                'accessToken'   => $accessToken,
            ];
            continue;
        }

        $body = $interactiveBody ?? trim((string)($message['text']['body'] ?? ''));
        if ($body === '') {
            continue;
        }

        // ── Bug 2 fix: deduplicación por Meta message ID ────────────────────────
        if ($msgId !== '') {
            $dup = $db->prepare("SELECT 1 FROM messages WHERE meta_message_id = :mid LIMIT 1");
            $dup->execute([':mid' => $msgId]);
            if ($dup->fetchColumn()) {
                error_log("Meta webhook: mensaje duplicado ignorado mid=$msgId");
                continue;
            }
        }

        $tenant              = $row;
        $tenant['_channel']  = 'whatsapp';
        $tenant['_meta_pid'] = $phoneNumberId;
        $tenantId            = (int)$row['id'];

        // Resolver o crear contacto
        $stmt = $db->prepare(
            "SELECT * FROM contacts WHERE tenant_id = :t AND phone = :p LIMIT 1"
        );
        $stmt->execute([':t' => $tenantId, ':p' => $customerWaId]);
        $contact = $stmt->fetch();

        if (!$contact) {
            $db->prepare(
                "INSERT INTO contacts (tenant_id, name, phone, channel)
                 VALUES (:t, :n, :p, 'whatsapp')"
            )->execute([':t' => $tenantId, ':n' => $profileName, ':p' => $customerWaId]);
            $contactId = (int)$db->lastInsertId();
        } else {
            $contactId = (int)$contact['id'];
            if ($contact['name'] === 'Cliente' && $profileName !== 'Cliente') {
                $db->prepare("UPDATE contacts SET name = :n WHERE id = :id")
                   ->execute([':n' => $profileName, ':id' => $contactId]);
            }
        }

        $conversationId = AgentService::findOrCreateConversation($db, $tenantId, $contactId, 'whatsapp');

        // Persiste mensaje (INSERT IGNORE si tenemos msgId — dedup de red-level)
        AgentService::persistInbound($db, $tenantId, $conversationId, $body, null, $msgId ?: null);
        AgentService::refreshWindow($db, $conversationId);

        $pendingText[] = [
            'phoneNumberId'  => $phoneNumberId,
            'customerWaId'   => $customerWaId,
            'accessToken'    => $accessToken,
            'tenant'         => $tenant,
            'tenantId'       => $tenantId,
            'contactId'      => $contactId,
            'conversationId' => $conversationId,
        ];
    }
}

// ── Fase 2: responder 200 a Meta ANTES de hacer las llamadas a Gemini ─────────
// Bug 3 fix: fastcgi_finish_request() se hace una sola vez, después del foreach.
http_response_code(200);
echo 'ok';
if (function_exists('fastcgi_finish_request')) {
    fastcgi_finish_request();
}

// ── Fase 3: enviar fallbacks de media (rápido, sin Gemini) ───────────────────
foreach ($pendingMedia as $pm) {
    MetaWhatsApp::sendText($pm['phoneNumberId'], $pm['customerWaId'], $pm['fallback'], $pm['accessToken']);
}

// ── Fase 4: procesar mensajes de texto con el agente ─────────────────────────
require_once dirname(__DIR__) . '/services/plan_guard.php';
foreach ($pendingText as $pt) {
    // ── WhatsApp feature gate: solo Growth/Pro puede usarlo ────────────────
    if (!PlanGuard::permite($pt['tenant'], 'whatsapp')) {
        $locale  = $pt['tenant']['locale'] ?? 'es';
        $gateMsg = ($locale === 'en')
            ? 'Hi! This business hasn\'t activated its WhatsApp plan yet. Please contact them through their website.'
            : 'Hola, este negocio aún no tiene WhatsApp activado en su plan. Contactalos por su sitio web.';
        MetaWhatsApp::sendText($pt['phoneNumberId'], $pt['customerWaId'], $gateMsg, $pt['accessToken']);
        error_log("Meta webhook: tenant {$pt['tenantId']} bloqueado por plan (whatsapp not allowed)");
        continue;
    }
    try {
        $result = AgentService::handleMessage(
            $db, $pt['tenant'], $pt['conversationId'], $pt['contactId']
        );
        MetaWhatsApp::sendText(
            $pt['phoneNumberId'], $pt['customerWaId'], $result['text'], $pt['accessToken']
        );
    } catch (Throwable $e) {
        error_log('Meta agent error: ' . $e->getMessage());
        AgentService::logError($db, $pt['tenantId'], 'meta_error', $e);

        $locale   = $pt['tenant']['locale'] ?? 'es';
        $errMsg   = ($locale === 'en')
            ? 'I\'m having a technical issue. Please try again in a moment.'
            : 'Estoy teniendo un problema técnico. Por favor intentá de nuevo en un momento.';
        MetaWhatsApp::sendText($pt['phoneNumberId'], $pt['customerWaId'], $errMsg, $pt['accessToken']);
    }
}
