<?php

namespace Modules\WhatsApp\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Log;
use Modules\WhatsApp\Entities\WaChannel;
use Modules\WhatsApp\Entities\WaContact;
use Modules\WhatsApp\Entities\WaMessage;

/**
 * Meta Cloud API webhook endpoint (public, no auth — Meta calls it).
 *   GET  : verification handshake.
 *   POST : inbound messages + delivery/read status callbacks.
 */
class WebhookController extends Controller
{
    /** Meta verification handshake: echo hub.challenge if the verify token matches. */
    public function verify(Request $request)
    {
        $mode      = $request->query('hub_mode');
        $token     = $request->query('hub_verify_token');
        $challenge = $request->query('hub_challenge');

        if ($mode === 'subscribe' && $this->tokenMatches($token)) {
            return response($challenge, 200);
        }

        return response('Forbidden', 403);
    }

    public function handle(Request $request)
    {
        $payload = $request->all();

        foreach (($payload['entry'] ?? []) as $entry) {
            foreach (($entry['changes'] ?? []) as $change) {
                $value = $change['value'] ?? [];
                $phoneNumberId = $value['metadata']['phone_number_id'] ?? null;
                $channel = $phoneNumberId
                    ? WaChannel::where('meta_phone_number_id', $phoneNumberId)->first()
                    : null;

                $this->handleStatuses($value['statuses'] ?? [], $channel);
                $this->handleInbound($value['messages'] ?? [], $value['contacts'] ?? [], $channel);
            }
        }

        // Meta expects a fast 200 regardless; failures are retried by Meta.
        return response()->json(['received' => true]);
    }

    private function handleStatuses(array $statuses, ?WaChannel $channel): void
    {
        foreach ($statuses as $status) {
            $id = $status['id'] ?? null;
            if (!$id) {
                continue;
            }

            $message = WaMessage::where('provider_message_id', $id)->first();
            if (!$message) {
                continue;
            }

            switch ($status['status'] ?? '') {
                case 'sent':
                    if ($message->status === 'queued' || $message->status === 'pending') {
                        $message->markSent($id);
                    }
                    break;
                case 'delivered':
                    $message->forceFill(['status' => 'delivered', 'delivered_at' => now()])->save();
                    WaContact::markWhatsApp((int) $message->business_id, (string) $message->wa_id, true);
                    break;
                case 'read':
                    $message->forceFill(['status' => 'read', 'read_at' => now()])->save();
                    WaContact::markWhatsApp((int) $message->business_id, (string) $message->wa_id, true);
                    break;
                case 'failed':
                    $code   = $status['errors'][0]['code'] ?? null;
                    $reason = $status['errors'][0]['title'] ?? 'Delivery failed at carrier.';
                    if (in_array($code, [131026, 131000, 1006])) {
                        $message->markNotOnWhatsApp('Not a WhatsApp user: ' . $reason);
                    } else {
                        $message->markFailed($reason);
                    }
                    break;
            }
        }
    }

    private function handleInbound(array $messages, array $contacts, ?WaChannel $channel): void
    {
        if (empty($messages)) {
            return;
        }

        $businessId = $channel?->business_id;
        if (!$businessId) {
            Log::warning('WhatsApp inbound for unknown phone_number_id; dropping.');
            return;
        }

        $nameByWaId = [];
        foreach ($contacts as $c) {
            if (!empty($c['wa_id'])) {
                $nameByWaId[$c['wa_id']] = $c['profile']['name'] ?? null;
            }
        }

        foreach ($messages as $msg) {
            $from = $msg['from'] ?? null;
            if (!$from) {
                continue;
            }

            $contact = WaContact::touchInbound($businessId, $from, $nameByWaId[$from] ?? null);

            $body = $msg['text']['body']
                ?? ($msg['button']['text'] ?? ($msg['interactive']['button_reply']['title'] ?? null));

            $inbound = WaMessage::create([
                'business_id'         => $businessId,
                'channel_id'          => $channel?->id,
                'contact_id'          => $contact->id,
                'wa_id'               => $from,
                'direction'           => 'in',
                'type'                => $msg['type'] ?? 'text',
                'body'                => $body,
                'payload'             => $msg,
                'status'              => 'received',
                'provider_message_id' => $msg['id'] ?? null,
                'source'              => 'inbound',
            ]);

            (new \Modules\WhatsApp\Entities\Services\ConversationService())->recordMessage($inbound);
            \Modules\WhatsApp\Jobs\ProcessInboundMessage::dispatch($inbound->id)
                ->onConnection(config('whatsapp.queue.connection', 'whatsapp_db'))
                ->onQueue(config('whatsapp.queue.queue', 'whatsapp'));
        }
    }

    /** A token matches if ANY channel uses it as its webhook verify token. */
    private function tokenMatches(?string $token): bool
    {
        if (empty($token)) {
            return false;
        }
        return WaChannel::where('meta_verify_token', $token)->exists();
    }
}
