<?php

namespace App\Console\Commands;

use App\Models\Appointment;
use App\Models\AppSetting;
use App\Notifications\AppointmentSoonPushNotification;
use App\Services\WhatsAppService;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Notification;

class SendAppointmentReminders extends Command
{
    protected $signature = 'appointments:send-reminders';

    protected $description = 'Web Push (N min antes) + WhatsApp (día anterior a horas fijas y/o N min antes, según ajustes)';

    public function handle(WhatsAppService $whatsApp): int
    {
        $tz = config('app.timezone');
        $now = Carbon::now($tz);

        $pushStats = $this->sendPushReminders($now, $tz);
        $waStats = ['day_client' => 0, 'day_barber' => 0, 'min_client' => 0, 'min_barber' => 0];

        if (filter_var(AppSetting::getValue('reminder_wa_enabled', '1'), FILTER_VALIDATE_BOOLEAN)) {
            if ($whatsApp->isConfigured()) {
                $waStats = array_merge($waStats, $this->sendWhatsAppDayBeforeReminders($whatsApp, $now, $tz));
                $waStats = array_merge($waStats, $this->sendWhatsAppMinutesReminders($whatsApp, $now, $tz));
            } else {
                $this->warn('WhatsApp no configurado (token / phone id); se omiten recordatorios WA.');
            }
        }

        $this->info(
            "Push: cliente {$pushStats['client']}, personal {$pushStats['barber']}. "
            ."WA día anterior: clientes {$waStats['day_client']}, personal {$waStats['day_barber']}. "
            ."WA minutos: clientes {$waStats['min_client']}, personal {$waStats['min_barber']}."
        );

        return self::SUCCESS;
    }

    /** @return array{client: int, barber: int} */
    private function sendPushReminders(Carbon $now, string $tz): array
    {
        $minutes = (int) AppSetting::getValue('reminder_minutes_before', '15');
        if ($minutes < 1) {
            $minutes = 15;
        }
        if ($minutes > 24 * 60) {
            $minutes = 24 * 60;
        }

        $notifyClient = filter_var(AppSetting::getValue('reminder_notify_client', '1'), FILTER_VALIDATE_BOOLEAN);
        $notifyBarber = filter_var(AppSetting::getValue('reminder_notify_barber', '1'), FILTER_VALIDATE_BOOLEAN);

        if (! $notifyClient && ! $notifyBarber) {
            return ['client' => 0, 'barber' => 0];
        }

        $appointments = Appointment::with(['client', 'barber.user', 'service'])
            ->whereIn('status', ['pending', 'confirmed'])
            ->whereDate('appointment_date', '>=', $now->toDateString())
            ->whereDate('appointment_date', '<=', $now->copy()->addDays(2)->toDateString())
            ->get();

        $sentClient = 0;
        $sentBarber = 0;

        foreach ($appointments as $appointment) {
            $dateStr = $appointment->appointment_date;
            if (is_string($dateStr) && strlen($dateStr) >= 10) {
                $dateStr = substr($dateStr, 0, 10);
            } else {
                continue;
            }

            $timeStr = $appointment->start_time;
            if ($timeStr === null || $timeStr === '') {
                continue;
            }
            if (is_string($timeStr) && strlen($timeStr) >= 5) {
                $timeStr = substr($timeStr, 0, 5);
            }

            try {
                $start = Carbon::parse($dateStr.' '.$timeStr, $tz);
            } catch (\Throwable) {
                continue;
            }

            $sendAt = $start->copy()->subMinutes($minutes);

            if ($now->lt($sendAt) || $now->gt($sendAt->copy()->addSeconds(90))) {
                continue;
            }

            $updates = [];

            if ($notifyClient && $appointment->client && $appointment->reminder_client_push_sent_at === null) {
                Notification::send(
                    $appointment->client,
                    new AppointmentSoonPushNotification($appointment, $minutes, 'client')
                );
                $updates['reminder_client_push_sent_at'] = $now;
                $sentClient++;
            }

            if ($notifyBarber && $appointment->barber?->user && $appointment->reminder_barber_push_sent_at === null) {
                Notification::send(
                    $appointment->barber->user,
                    new AppointmentSoonPushNotification($appointment, $minutes, 'barber')
                );
                $updates['reminder_barber_push_sent_at'] = $now;
                $sentBarber++;
            }

            if (! empty($updates)) {
                $appointment->forceFill($updates)->save();
            }
        }

        return ['client' => $sentClient, 'barber' => $sentBarber];
    }

    /**
     * Recordatorio plantilla para citas del día siguiente, en cada horario configurado (ej. 08:00).
     *
     * @return array{day_client: int, day_barber: int}
     */
    private function sendWhatsAppDayBeforeReminders(WhatsAppService $whatsApp, Carbon $now, string $tz): array
    {
        if (! filter_var(AppSetting::getValue('reminder_wa_day_before_enabled', '1'), FILTER_VALIDATE_BOOLEAN)) {
            return ['day_client' => 0, 'day_barber' => 0];
        }

        $times = $this->parseWaDayBeforeTimes(AppSetting::getValue('reminder_wa_day_before_times', '08:00'));
        if ($times === []) {
            return ['day_client' => 0, 'day_barber' => 0];
        }

        $nowHm = $now->format('H:i');
        if (! in_array($nowHm, $times, true)) {
            return ['day_client' => 0, 'day_barber' => 0];
        }

        $notifyClient = filter_var(AppSetting::getValue('reminder_wa_day_before_client', '1'), FILTER_VALIDATE_BOOLEAN);
        $notifyBarber = filter_var(AppSetting::getValue('reminder_wa_day_before_barber', '0'), FILTER_VALIDATE_BOOLEAN);

        if (! $notifyClient && ! $notifyBarber) {
            return ['day_client' => 0, 'day_barber' => 0];
        }

        $tomorrow = Carbon::tomorrow($tz)->toDateString();

        $appointments = Appointment::with(['client', 'barber.user', 'service'])
            ->whereIn('status', ['pending', 'confirmed'])
            ->whereDate('appointment_date', $tomorrow)
            ->get();

        $dayClient = 0;
        $dayBarber = 0;

        foreach ($appointments as $appointment) {
            $updates = [];

            if ($notifyClient && $appointment->client?->phone && $appointment->wa_reminder_day_before_client_sent_at === null) {
                if ($whatsApp->sendAppointmentReminder($appointment)) {
                    $updates['wa_reminder_day_before_client_sent_at'] = $now;
                    $dayClient++;
                }
            }

            if ($notifyBarber && $appointment->barber?->user && $appointment->wa_reminder_day_before_barber_sent_at === null) {
                if ($whatsApp->sendAppointmentReminderToBarber($appointment)) {
                    $updates['wa_reminder_day_before_barber_sent_at'] = $now;
                    $dayBarber++;
                }
            }

            if (! empty($updates)) {
                $appointment->forceFill($updates)->save();
            }
        }

        return ['day_client' => $dayClient, 'day_barber' => $dayBarber];
    }

    /**
     * Misma ventana que push pero usando minutos propios de WA (0 = desactivado).
     *
     * @return array{min_client: int, min_barber: int}
     */
    private function sendWhatsAppMinutesReminders(WhatsAppService $whatsApp, Carbon $now, string $tz): array
    {
        $waMinutes = (int) AppSetting::getValue('reminder_wa_minutes_before', '0');
        if ($waMinutes < 1) {
            return ['min_client' => 0, 'min_barber' => 0];
        }
        if ($waMinutes > 24 * 60) {
            $waMinutes = 24 * 60;
        }

        $notifyClient = filter_var(AppSetting::getValue('reminder_wa_minutes_client', '1'), FILTER_VALIDATE_BOOLEAN);
        $notifyBarber = filter_var(AppSetting::getValue('reminder_wa_minutes_barber', '0'), FILTER_VALIDATE_BOOLEAN);

        if (! $notifyClient && ! $notifyBarber) {
            return ['min_client' => 0, 'min_barber' => 0];
        }

        $appointments = Appointment::with(['client', 'barber.user', 'service'])
            ->whereIn('status', ['pending', 'confirmed'])
            ->whereDate('appointment_date', '>=', $now->toDateString())
            ->whereDate('appointment_date', '<=', $now->copy()->addDays(2)->toDateString())
            ->get();

        $minClient = 0;
        $minBarber = 0;

        foreach ($appointments as $appointment) {
            $dateStr = $appointment->appointment_date;
            if (is_string($dateStr) && strlen($dateStr) >= 10) {
                $dateStr = substr($dateStr, 0, 10);
            } else {
                continue;
            }

            $timeStr = $appointment->start_time;
            if ($timeStr === null || $timeStr === '') {
                continue;
            }
            if (is_string($timeStr) && strlen($timeStr) >= 5) {
                $timeStr = substr($timeStr, 0, 5);
            }

            try {
                $start = Carbon::parse($dateStr.' '.$timeStr, $tz);
            } catch (\Throwable) {
                continue;
            }

            $sendAt = $start->copy()->subMinutes($waMinutes);

            if ($now->lt($sendAt) || $now->gt($sendAt->copy()->addSeconds(90))) {
                continue;
            }

            $updates = [];

            if ($notifyClient && $appointment->client?->phone && $appointment->wa_reminder_minutes_client_sent_at === null) {
                if ($whatsApp->sendAppointmentReminder($appointment)) {
                    $updates['wa_reminder_minutes_client_sent_at'] = $now;
                    $minClient++;
                }
            }

            if ($notifyBarber && $appointment->barber?->user && $appointment->wa_reminder_minutes_barber_sent_at === null) {
                if ($whatsApp->sendAppointmentReminderToBarber($appointment)) {
                    $updates['wa_reminder_minutes_barber_sent_at'] = $now;
                    $minBarber++;
                }
            }

            if (! empty($updates)) {
                $appointment->forceFill($updates)->save();
            }
        }

        return ['min_client' => $minClient, 'min_barber' => $minBarber];
    }

    /**
     * @return list<string> Horarios HH:MM
     */
    private function parseWaDayBeforeTimes(?string $raw): array
    {
        if ($raw === null || trim($raw) === '') {
            return ['08:00'];
        }

        $parts = preg_split('/[\s,]+/', trim($raw), -1, PREG_SPLIT_NO_EMPTY);
        $out = [];
        foreach ($parts as $p) {
            if (! preg_match('/^(\d{1,2}):(\d{2})$/', $p, $m)) {
                continue;
            }
            $h = (int) $m[1];
            $min = (int) $m[2];
            if ($h < 0 || $h > 23 || $min < 0 || $min > 59) {
                continue;
            }
            $out[] = sprintf('%02d:%02d', $h, $min);
        }

        return array_values(array_unique($out));
    }
}
