<?php

namespace App\Controllers;

use App\Models\Control\TenantRecordModel;
use Throwable;

/**
 * Meta WhatsApp Cloud API's inbound webhook — the one thing WhatsAppService
 * couldn't do before this feature (see its own class doc comment). Mirrors
 * PaymentWebhookController's exact pattern: no session/subdomain/CSRF
 * (see webhooks/* in Filters.php), tenant resolved explicitly from a URL
 * segment, every POST always answered 200 once parsed (even on business-
 * logic failure) so Meta doesn't retry-storm us, malformed JSON caught
 * and answered 400 rather than crashing.
 *
 * verify() is Meta's one-time (and re-triggerable) subscription handshake
 * — a GET with hub.mode/hub.verify_token/hub.challenge, answered by
 * echoing back the challenge only if the token matches this tenant's own
 * configured whatsapp.webhook_verify_token setting. incoming() is the
 * real per-message POST; all the routing/AI/guardrail logic lives in
 * ConciergeService, this controller only extracts the real message(s)
 * from Meta's payload shape and hands them off.
 *
 * Scope note: only type=='text' inbound messages are handled in this
 * version — an image/audio/location message is logged and acknowledged
 * but not routed to the AI (there's no real content to ground a reply
 * in), and a 'statuses' webhook (delivery/read receipts, not a new
 * message) is acknowledged and ignored.
 */
class ConciergeWebhookController extends BaseController
{
    public function verify(string $tenantSlug)
    {
        if (! $this->resolveTenant($tenantSlug)) {
            return $this->response->setStatusCode(404)->setBody('Unknown tenant');
        }

        // Meta sends these as hub.mode/hub.verify_token/hub.challenge, but
        // PHP automatically converts dots in query-string keys to
        // underscores when populating $_GET — so these are the real names
        // CodeIgniter sees, not a typo.
        $mode      = $this->request->getGet('hub_mode');
        $token     = $this->request->getGet('hub_verify_token');
        $challenge = $this->request->getGet('hub_challenge');

        $expected = service('settings')->get('whatsapp.webhook_verify_token');

        if ($mode === 'subscribe' && $expected !== null && $token === $expected) {
            return $this->response->setStatusCode(200)->setBody((string) $challenge);
        }

        log_message('warning', "ConciergeWebhookController: verification failed for {$tenantSlug}.");

        return $this->response->setStatusCode(403)->setBody('Verification failed');
    }

    public function incoming(string $tenantSlug)
    {
        if (! $this->resolveTenant($tenantSlug)) {
            return $this->response->setStatusCode(404)->setJSON(['error' => 'Unknown tenant']);
        }

        try {
            $payload = $this->request->getJSON(true) ?? [];
        } catch (Throwable $e) {
            log_message('warning', 'WhatsApp Concierge webhook: invalid JSON body — ' . $e->getMessage());

            return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid JSON body']);
        }

        log_message('info', 'WhatsApp Concierge webhook received: ' . json_encode($payload));

        foreach ($payload['entry'] ?? [] as $entry) {
            foreach ($entry['changes'] ?? [] as $change) {
                $value = $change['value'] ?? [];

                foreach ($value['messages'] ?? [] as $message) {
                    $this->handleOneMessage($message);
                }
            }
        }

        return $this->response->setStatusCode(200)->setJSON(['received' => true]);
    }

    private function handleOneMessage(array $message): void
    {
        $from = $message['from'] ?? null;
        $id   = $message['id'] ?? null;
        $type = $message['type'] ?? null;

        if ($from === null) {
            return;
        }

        if ($type !== 'text') {
            log_message('info', "ConciergeWebhookController: ignoring unsupported inbound message type '{$type}' from {$from}.");

            return;
        }

        $body = $message['text']['body'] ?? null;

        if ($body === null || trim($body) === '') {
            return;
        }

        try {
            service('conciergeService')->handleInboundMessage($from, $body, $id);
        } catch (Throwable $e) {
            // A failure here must not surface as a 500 to Meta (see class
            // doc comment) — logged for real investigation instead.
            log_message('error', 'ConciergeWebhookController: handleInboundMessage failed — ' . $e->getMessage());
        }
    }

    private function resolveTenant(string $slug): bool
    {
        $tenant = (new TenantRecordModel())->findActiveBySlug($slug);

        if ($tenant === null) {
            return false;
        }

        service('tenantContext')->setTenant($tenant);

        return true;
    }
}
