<?php

namespace App\Services;

use App\Models\Appointment;
use App\Support\WhatsAppConfig;
use App\Support\WhatsAppMessageCopy;
use Carbon\Carbon;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class WhatsAppService
{
    protected ?string $lastError = null;

    public function isConfigured(): bool
    {
        return ! empty(WhatsAppConfig::accessToken()) && ! empty(WhatsAppConfig::phoneNumberId());
    }

    /**
     * Send template message (required for business-initiated conversations).
     */
    public function sendTemplate(string $to, string $templateName, array $components = []): bool
    {
        if (!$this->isConfigured()) {
            return false;
        }

        $payload = [
            'messaging_product' => 'whatsapp',
            'recipient_type' => 'individual',
            'to' => preg_replace('/[^0-9]/', '', $to),
            'type' => 'template',
            'template' => [
                'name' => $templateName,
                'language' => ['code' => $templateName === 'hello_world' ? 'en_US' : 'es'],
            ],
        ];

        if (!empty($components)) {
            $payload['template']['components'] = $components;
        }

        $response = Http::withToken(WhatsAppConfig::accessToken())
            ->post(WhatsAppConfig::baseUrl() . '/' . WhatsAppConfig::phoneNumberId() . '/messages', $payload);

        if (!$response->successful()) {
            $json = $response->json();
            $json = is_array($json) ? $json : [];
            $this->lastError = $json['error']['message'] ?? $response->body();
            $this->logFailedMessageSend('template send', $to, $json);

            return false;
        }

        $this->lastError = null;
        return true;
    }

    public function getLastError(): ?string
    {
        return $this->lastError;
    }

    /**
     * Send interactive list (within 24h of user message).
     */
    public function sendList(string $to, string $body, string $buttonText, array $sections, bool $logBotOutbound = true): bool
    {
        if (!$this->isConfigured()) {
            return false;
        }

        $body = $this->truncateInteractiveBody($body);
        $buttonText = $this->truncateListButton($buttonText);
        $sections = $this->truncateListSections($sections);

        $payload = [
            'messaging_product' => 'whatsapp',
            'recipient_type' => 'individual',
            'to' => preg_replace('/[^0-9]/', '', $to),
            'type' => 'interactive',
            'interactive' => [
                'type' => 'list',
                'body' => ['text' => $body],
                'action' => [
                    'button' => $buttonText,
                    'sections' => $sections,
                ],
            ],
        ];

        $response = Http::withToken(WhatsAppConfig::accessToken())
            ->post(WhatsAppConfig::baseUrl() . '/' . WhatsAppConfig::phoneNumberId() . '/messages', $payload);

        if (!$response->successful()) {
            $json = $response->json();
            $json = is_array($json) ? $json : [];
            $this->lastError = $json['error']['message'] ?? $response->body();
            $this->logFailedMessageSend('list send', $to, $json);

            return false;
        }

        $this->lastError = null;
        if ($logBotOutbound) {
            WhatsAppMessageLogger::outboundBot($to, 'list', $body, ['button' => $buttonText]);
        }

        return true;
    }

    /**
     * Send interactive buttons (within 24h of user message).
     */
    public function sendButtons(string $to, string $body, array $buttons, bool $logBotOutbound = true): bool
    {
        if (!$this->isConfigured()) {
            Log::warning('WhatsApp sendButtons skipped: not configured');
            return false;
        }

        $body = $this->truncateInteractiveBody($body);

        $rows = [];
        foreach (array_slice($buttons, 0, 3) as $id => $label) {
            $title = Str::limit((string) $label, 20, '');
            $rows[] = ['type' => 'reply', 'reply' => ['id' => (string) $id, 'title' => $title]];
        }

        $payload = [
            'messaging_product' => 'whatsapp',
            'recipient_type' => 'individual',
            'to' => preg_replace('/[^0-9]/', '', $to),
            'type' => 'interactive',
            'interactive' => [
                'type' => 'button',
                'body' => ['text' => $body],
                'action' => ['buttons' => $rows],
            ],
        ];

        $response = Http::withToken(WhatsAppConfig::accessToken())
            ->post(WhatsAppConfig::baseUrl() . '/' . WhatsAppConfig::phoneNumberId() . '/messages', $payload);

        if (!$response->successful()) {
            $json = $response->json();
            $json = is_array($json) ? $json : [];
            $this->lastError = $json['error']['message'] ?? $response->body();
            $this->logFailedMessageSend('buttons send', $to, $json);

            return false;
        }

        $this->lastError = null;
        if ($logBotOutbound) {
            WhatsAppMessageLogger::outboundBot($to, 'buttons', $body, []);
        }

        return true;
    }

    /**
     * @param  array<string, mixed>  $json
     */
    private function logFailedMessageSend(string $context, string $to, array $json): void
    {
        $code = $json['error']['code'] ?? null;
        $msg = isset($json['error']['message']) ? (string) $json['error']['message'] : '';
        $lower = strtolower($msg);
        $tokenIssue = $code === 190 || $code === 463 || $code === 102
            || str_contains($lower, 'expired')
            || str_contains($lower, 'invalid oauth')
            || str_contains($lower, 'session has expired');

        Log::error('WhatsApp '.$context.' failed', [
            'to' => $to,
            'error_code' => $code,
            'fbtrace_id' => $json['error']['fbtrace_id'] ?? null,
            'message' => $msg !== '' ? $msg : null,
            'response' => $json,
        ]);

        if ($tokenIssue) {
            Log::warning(
                'WhatsApp: el access token parece inválido o vencido. En Meta for Developers → WhatsApp → API Setup generá un token nuevo y guardalo en Admin → WhatsApp → Access token.'
            );
        }
    }

    /** Meta: interactive body (list / buttons) máx. 1024 caracteres. */
    private function truncateInteractiveBody(string $text): string
    {
        if (Str::length($text) <= 1024) {
            return $text;
        }
        Log::warning('WhatsApp: truncating interactive body to 1024 chars (API limit)');

        return Str::limit($text, 1024, '…');
    }

    /** Meta: list action button máx. 20 caracteres. */
    private function truncateListButton(string $text): string
    {
        if (Str::length($text) <= 20) {
            return $text;
        }
        Log::warning('WhatsApp: truncating list button label to 20 chars (API limit)');

        return Str::limit($text, 20, '');
    }

    /**
     * Meta: título de sección máx. 24; título de fila 24; descripción 72.
     *
     * @param  array<int, array<string, mixed>>  $sections
     * @return array<int, array<string, mixed>>
     */
    private function truncateListSections(array $sections): array
    {
        $out = [];
        foreach ($sections as $section) {
            if (! is_array($section)) {
                continue;
            }
            $s = $section;
            if (isset($s['title'])) {
                $s['title'] = Str::limit((string) $s['title'], 24, '');
            }
            $rows = [];
            foreach ($section['rows'] ?? [] as $row) {
                if (! is_array($row)) {
                    continue;
                }
                $r = $row;
                if (isset($r['title'])) {
                    $r['title'] = Str::limit((string) $r['title'], 24, '');
                }
                if (isset($r['description'])) {
                    $r['description'] = Str::limit((string) $r['description'], 72, '');
                }
                $rows[] = $r;
            }
            $s['rows'] = $rows;
            $out[] = $s;
        }

        return $out;
    }

    /**
     * Send text message (only works within 24h of user's last message).
     *
     * @param  bool  $logBotOutbound  Si false, no registra en el historial (p. ej. envío manual desde admin).
     */
    public function sendText(string $to, string $text, bool $logBotOutbound = true): bool
    {
        if (!$this->isConfigured()) {
            Log::warning('WhatsApp sendText skipped: not configured', [
                'token_set' => ! empty(WhatsAppConfig::accessToken()),
                'phone_id_set' => ! empty(WhatsAppConfig::phoneNumberId()),
            ]);
            return false;
        }

        $text = Str::limit($text, 4096, '');

        $response = Http::withToken(WhatsAppConfig::accessToken())
            ->post(WhatsAppConfig::baseUrl() . '/' . WhatsAppConfig::phoneNumberId() . '/messages', [
                'messaging_product' => 'whatsapp',
                'recipient_type' => 'individual',
                'to' => preg_replace('/[^0-9]/', '', $to),
                'type' => 'text',
                'text' => ['body' => $text],
            ]);

        if (!$response->successful()) {
            $json = $response->json();
            $json = is_array($json) ? $json : [];
            $this->lastError = $json['error']['message'] ?? $response->body();
            $this->logFailedMessageSend('text send', $to, $json);

            return false;
        }

        $this->lastError = null;
        if ($logBotOutbound) {
            WhatsAppMessageLogger::outboundBot($to, 'text', $text, []);
        }

        return true;
    }

    /**
     * Send appointment confirmation to client (uses template reserva_confirmada).
     */
    public function sendAppointmentConfirmation(Appointment $appointment): bool
    {
        $client = $appointment->client;
        $phone = $client?->phone;
        if (!$phone) {
            return false;
        }

        $serviceName = $appointment->service?->name ?? 'Servicio';
        $barberName = $appointment->barber?->user?->name ?? 'Barbero';
        $dateFormatted = Carbon::parse($appointment->appointment_date)->format('d/m/Y');
        $time = $appointment->start_time;

        $components = [
            [
                'type' => 'body',
                'parameters' => [
                    ['type' => 'text', 'text' => $serviceName],
                    ['type' => 'text', 'text' => $barberName],
                    ['type' => 'text', 'text' => $dateFormatted],
                    ['type' => 'text', 'text' => $time],
                ],
            ],
        ];

        return $this->sendTemplate($phone, 'reserva_confirmada', $components);
    }

    /**
     * Mensaje de sesión (texto) con detalle de la cita y estado pendiente — fiable tras reserva por WhatsApp.
     */
    public function sendPendingBookingConfirmationText(Appointment $appointment): bool
    {
        $appointment->load(['client', 'service', 'barber.user']);
        $phone = $appointment->client?->phone;
        if (! $phone) {
            return false;
        }

        return $this->sendText($phone, WhatsAppMessageCopy::pendingBooking($appointment));
    }

    /**
     * Recordatorio (plantilla recordatorio_cita): servicio, profesional, fecha y hora — mismo orden que reserva_confirmada.
     */
    public function sendAppointmentReminder(Appointment $appointment): bool
    {
        $appointment->load(['client', 'service', 'barber.user']);
        $client = $appointment->client;
        $phone = $client?->phone;
        if (!$phone) {
            return false;
        }

        $components = $this->recordatorioCitaTemplateComponents($appointment);

        return $this->sendTemplate($phone, 'recordatorio_cita', $components);
    }

    /**
     * Misma plantilla recordatorio_cita, al teléfono del usuario barbero (opcional).
     */
    public function sendAppointmentReminderToBarber(Appointment $appointment): bool
    {
        $appointment->load(['service', 'barber.user']);
        $phone = $appointment->barber?->user?->phone;
        if (! $phone) {
            return false;
        }

        $components = $this->recordatorioCitaTemplateComponents($appointment);

        return $this->sendTemplate($phone, 'recordatorio_cita', $components);
    }

    /**
     * Parámetros del cuerpo de plantilla recordatorio_cita: {{1}}–{{4}} = servicio, profesional, fecha dd/mm/aaaa, hora.
     *
     * @return array<int, array<string, mixed>>
     */
    private function recordatorioCitaTemplateComponents(Appointment $appointment): array
    {
        $serviceName = $appointment->service?->name ?? 'Servicio';
        $barberName = $appointment->barber?->user?->name ?? 'Barbero';
        $dateFormatted = Carbon::parse($appointment->appointment_date)->format('d/m/Y');
        $time = $appointment->start_time ?? '';

        return [
            [
                'type' => 'body',
                'parameters' => [
                    ['type' => 'text', 'text' => $serviceName],
                    ['type' => 'text', 'text' => $barberName],
                    ['type' => 'text', 'text' => $dateFormatted],
                    ['type' => 'text', 'text' => (string) $time],
                ],
            ],
        ];
    }
}
