<?php

namespace App\Console\Commands;

use App\Models\Device;
use App\Models\Event;
use App\Models\Notification;
use App\Models\Task;
use App\Services\PushService;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class ScheduleEventReminders extends Command
{
    protected $signature = 'reminders:schedule';

    protected $description = 'Dispatcht fällige Event-Reminder (läuft jede Minute)';

    public function handle(): void
    {
        $now         = now();
        $minuteStart = $now->copy()->startOfMinute();
        $minuteEnd   = $now->copy()->endOfMinute();

        $this->processTaskReminders($minuteStart, $minuteEnd);

        $events = Event::with('user')
            ->where('starts_at', '>', $now)
            ->where('starts_at', '<', $now->copy()->addDay())
            ->get();

        Log::info('reminders:schedule run', [
            'now_utc'      => $now->toDateTimeString(),
            'window_utc'   => $minuteEnd->toDateTimeString(),
            'events_found' => $events->count(),
        ]);

        foreach ($events as $event) {
            $user = $event->user;
            if (!$user) continue;

            $tz = $user->timezone ?? 'Europe/Vienna';

            // ══════════════════════════════════════
            // PFAD A — Event hat eigene Reminder
            // ══════════════════════════════════════
            $eventReminders = $event->reminders ?? [];
            if (is_string($eventReminders)) {
                $eventReminders = json_decode($eventReminders, true) ?? [];
            }

            if (!empty($eventReminders)) {
                foreach ($eventReminders as $reminder) {
                    $sendAt = $this->calculateSendTime($event, $reminder, $tz);

                    if (!$sendAt || !$sendAt->between($minuteStart, $minuteEnd)) {
                        continue;
                    }

                    $hash = md5(json_encode($reminder));
                    $sent = DB::table('sent_reminders')
                        ->where('event_id', $event->id)
                        ->where('reminder_hash', $hash)
                        ->exists();
                    if ($sent) continue;

                    $this->sendEventReminder($user, $event, $reminder, $tz);

                    DB::table('sent_reminders')->insert([
                        'id'            => (string) Str::uuid(),
                        'event_id'      => $event->id,
                        'reminder_hash' => $hash,
                        'sent_at'       => now(),
                    ]);
                }
                continue;
            }

            // ══════════════════════════════════════
            // PFAD B — Globale Automation
            // ══════════════════════════════════════
            $globalAuto = $user->automations()
                ->where('type', 'event_reminder')
                ->where('active', true)
                ->first();

            if (!$globalAuto) continue;

            $minutesBefore = $globalAuto->cfg('minutes_before', 30);
            $reminder = [
                'type'    => 'before',
                'minutes' => $minutesBefore,
            ];

            $sendAt = $this->calculateSendTime($event, $reminder, $tz);

            if (!$sendAt || !$sendAt->between($minuteStart, $minuteEnd)) {
                continue;
            }

            $hash = md5('global_' . $minutesBefore);
            $sent = DB::table('sent_reminders')
                ->where('event_id', $event->id)
                ->where('reminder_hash', $hash)
                ->exists();
            if ($sent) continue;

            $this->sendEventReminder($user, $event, $reminder, $tz);

            DB::table('sent_reminders')->insert([
                'id'            => (string) Str::uuid(),
                'event_id'      => $event->id,
                'reminder_hash' => $hash,
                'sent_at'       => now(),
            ]);
        }
    }

    private function sendEventReminder(\App\Models\User $user, Event $event, array $reminder, string $tz): void
    {
        $start   = $event->starts_at->setTimezone($tz);
        $diffMin = (int) now($tz)->diffInMinutes($start, false);

        $body = match (true) {
            $diffMin <= 0   => 'Jetzt!',
            $diffMin < 60   => 'In ' . $diffMin . ' Minuten',
            $diffMin < 1440 => 'In ' . intval($diffMin / 60) . ' Stunde(n)',
            default         => 'Morgen um ' . $start->format('H:i') . ' Uhr',
        };

        Log::info('Event push sending', [
            'event'    => $event->title,
            'diff_min' => $diffMin,
            'body'     => $body,
        ]);

        $hasPushToken = Device::where('user_id', $user->id)
            ->where('active', true)
            ->whereNotNull('push_token')
            ->exists();

        if ($hasPushToken) {
            PushService::send(
                $user,
                'Erinnerung: ' . $event->title,
                $body,
                ['type' => 'event_reminder', 'event_id' => $event->id]
            );
        }

        Notification::create([
            'user_id' => $user->id,
            'type'    => 'event_reminder',
            'title'   => $event->title,
            'message' => $body,
            'data'    => ['event_id' => $event->id, 'reminder' => $reminder],
        ]);

        Log::info('Event reminder sent', ['user' => $user->name, 'event' => $event->title]);
    }

    private function processTaskReminders(Carbon $minuteStart, Carbon $minuteEnd): void
    {
        $tasks = Task::with('user')
            ->whereNotNull('reminder_at')
            ->where('reminder_at', '>=', $minuteStart)
            ->where('reminder_at', '<=', $minuteEnd)
            ->where('reminder_sent', false)
            ->where('status', '!=', 'done')
            ->get();

        foreach ($tasks as $task) {
            $user = $task->user;
            if (!$user) continue;

            $tz = $user->timezone ?? 'Europe/Vienna';

            $body = $task->due_at
                ? 'Fällig: ' . $task->due_at->setTimezone($tz)->format('H:i') . ' Uhr'
                : 'Aufgabe erledigen';

            $hasPushToken = Device::where('user_id', $user->id)
                ->where('active', true)
                ->whereNotNull('push_token')
                ->exists();

            if ($hasPushToken) {
                PushService::send(
                    $user,
                    'Erinnerung: ' . $task->title,
                    $body,
                    ['type' => 'task_reminder', 'task_id' => $task->id]
                );
            }

            Notification::create([
                'user_id' => $user->id,
                'type'    => 'task_reminder',
                'title'   => $task->title,
                'message' => $body,
                'data'    => ['task_id' => $task->id],
            ]);

            $task->update(['reminder_sent' => true]);

            Log::info('Task reminder sent', ['user' => $user->name, 'task' => $task->title]);
        }
    }

    private function calculateSendTime(Event $event, array $reminder, string $tz): ?Carbon
    {
        $startUtc = $event->starts_at;

        $sendAt = match ($reminder['type']) {
            'before' => $startUtc->copy()->subMinutes($reminder['minutes'] ?? 30),

            'time_of_day' => Carbon::createFromFormat(
                'Y-m-d H:i',
                $event->starts_at->setTimezone($tz)->format('Y-m-d') . ' ' . ($reminder['time'] ?? '08:00'),
                $tz
            )->utc(),

            'day_before' => Carbon::createFromFormat(
                'Y-m-d H:i',
                $event->starts_at->setTimezone($tz)->subDay()->format('Y-m-d') . ' ' . ($reminder['time'] ?? '18:00'),
                $tz
            )->utc(),

            default => null,
        };

        Log::info('calculateSendTime', [
            'event'       => $event->title,
            'reminder'    => $reminder,
            'starts_utc'  => $startUtc->toDateTimeString(),
            'send_at_utc' => $sendAt?->toDateTimeString(),
            'now_utc'     => now()->toDateTimeString(),
            'diff_min'    => $sendAt ? round(now()->diffInSeconds($sendAt, false) / 60, 2) : null,
        ]);

        return $sendAt;
    }
}
