<?php

namespace App\Jobs;

use App\Models\Demo;
use App\Services\GoogleCalendarService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Throwable;

class SyncDemoToGoogleCalendar implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;
    public array $backoff = [10, 30, 60]; // Exponential backoff
    public int $timeout = 60;

    public function __construct(
        private readonly int $demoId,
        private readonly string $operation, // 'create', 'update', 'delete', 'start', 'complete', 'cancel', 'reschedule'
        private readonly array $payload = []
    ) {}

    public function handle(): void
    {
        $demo = Demo::with([
            'lead:id,name,email',
            'demo_assignees.user:id,email',
            'demo_current_schedule',
        ])->find($this->demoId);

        if (!$demo || $demo->is_deleted) {
            Log::warning("[GoogleCalendar] Demo {$this->demoId} not found or deleted");
            return;
        }

        $service = new GoogleCalendarService();

        try {
            match ($this->operation) {
                'create' => $this->createEvent($service, $demo),
                'update' => $this->updateEvent($service, $demo),
                'delete' => $this->deleteEvent($service, $demo),
                'start' => $this->markStarted($service, $demo),
                'complete' => $this->markCompleted($service, $demo),
                'cancel' => $this->markCancelled($service, $demo),
                'reschedule' => $this->rescheduleEvent($service, $demo),
                default => throw new \InvalidArgumentException("Unknown operation: {$this->operation}")
            };
        } catch (Throwable $e) {
            Log::error("[GoogleCalendar] {$this->operation} failed for demo {$this->demoId}: " . $e->getMessage());
            throw $e; // Let Laravel retry
        }
    }

    private function createEvent(GoogleCalendarService $service, Demo $demo): void
    {
        if ($demo->google_event_id) {
            Log::info("[GoogleCalendar] Demo {$demo->id} already has event {$demo->google_event_id}");
            return;
        }

        $schedule = $demo->demo_current_schedule;
        if (!$schedule) {
            throw new \RuntimeException('No schedule found for demo');
        }

        $startDateTime = $schedule->schedule_date->format('c');
        $endDateTime = $schedule->schedule_date->clone()->addHour()->format('c');

        // Build attendees
        $attendees = [];
        if ($demo->lead?->email) {
            $attendees[] = $demo->lead->email;
        }
        foreach ($demo->demo_assignees as $assignee) {
            if ($assignee->user?->email) {
                $attendees[] = $assignee->user->email;
            }
        }

        // Build description
        $productNames = $this->payload['product_names'] ?? [];
        $productLines = implode("\n", array_map(fn($name) => "- {$name}", $productNames));
        $description = ($demo->description ?: "Demo scheduled with Blue Waves Media") .
            "\n\nProducts:\n{$productLines}\n\nDownload Brochure:\nhttps://crm.workcentra.com/assets/pdf/Bluewaves.pdf";

        $event = $service->createEvent(
            summary: "Blue Waves Demo",
            description: $description,
            startDateTime: $startDateTime,
            endDateTime: $endDateTime,
            attendees: array_unique(array_filter($attendees)),
            timeZone: 'Asia/Kolkata'
        );

        // Update demo with event ID (use direct query to avoid model events)
        Demo::where('id', $demo->id)->update([
            'google_event_id' => $event['event_id'],
            'meeting_link' => $event['meeting_link'],
        ]);

        // Clear cache
        Cache::forget("demo:{$demo->id}:calendar");

        Log::info("[GoogleCalendar] Created event {$event['event_id']} for demo {$demo->id}");
    }

    private function updateEvent(GoogleCalendarService $service, Demo $demo): void
    {
        if (!$demo->google_event_id) {
            Log::warning("[GoogleCalendar] Demo {$demo->id} has no google_event_id for update");
            return;
        }

        $schedule = $demo->demo_current_schedule;
        if (!$schedule) {
            return;
        }

        $startDateTime = $schedule->schedule_date->format('c');
        $endDateTime = $schedule->schedule_date->clone()->addHour()->format('c');

        $service->updateEvent($demo->google_event_id, [
            'start' => $startDateTime,
            'end' => $endDateTime,
            'timeZone' => 'Asia/Kolkata',
        ]);

        Cache::forget("demo:{$demo->id}:calendar");
        Log::info("[GoogleCalendar] Updated event {$demo->google_event_id} for demo {$demo->id}");
    }

    private function deleteEvent(GoogleCalendarService $service, Demo $demo): void
    {
        if (!$demo->google_event_id) {
            return;
        }

        $service->deleteEvent($demo->google_event_id);

        // Clear event reference
        Demo::where('id', $demo->id)->update([
            'google_event_id' => null,
            'meeting_link' => null,
        ]);

        Cache::forget("demo:{$demo->id}:calendar");
        Log::info("[GoogleCalendar] Deleted event {$demo->google_event_id} for demo {$demo->id}");
    }

    private function markStarted(GoogleCalendarService $service, Demo $demo): void
    {
        if (!$demo->google_event_id) {
            return;
        }

        $service->updateEvent($demo->google_event_id, [
            'summary' => 'Blue Waves Demo (Started)',
            'description' => ($demo->description ?? '') . "\n\nStatus: Started at " . now()->format('Y-m-d H:i:s'),
        ]);

        Log::info("[GoogleCalendar] Marked event {$demo->google_event_id} as started");
    }

    private function markCompleted(GoogleCalendarService $service, Demo $demo): void
    {
        if (!$demo->google_event_id) {
            return;
        }

        $service->updateEvent($demo->google_event_id, [
            'summary' => 'Blue Waves Demo (Completed)',
            'description' => ($demo->description ?? '') . "\n\nCompleted at: " . now()->format('Y-m-d H:i:s'),
        ]);

        Log::info("[GoogleCalendar] Marked event {$demo->google_event_id} as completed");
    }

    private function markCancelled(GoogleCalendarService $service, Demo $demo): void
    {
        if (!$demo->google_event_id) {
            return;
        }

        $remark = $this->payload['remark'] ?? 'No reason provided';

        $service->updateEvent($demo->google_event_id, [
            'summary' => 'Blue Waves Demo (Cancelled)',
            'description' => ($demo->description ?? '') .
                "\n\nCancelled at: " . now()->format('Y-m-d H:i:s') .
                "\nReason: " . $remark,
        ]);

        Log::info("[GoogleCalendar] Marked event {$demo->google_event_id} as cancelled");
    }

    private function rescheduleEvent(GoogleCalendarService $service, Demo $demo): void
    {
        if (!$demo->google_event_id) {
            Log::warning("[GoogleCalendar] Demo {$demo->id} has no google_event_id for reschedule");
            return;
        }

        $newDate = $this->payload['new_date'] ?? null;
        $newTime = $this->payload['new_time'] ?? null;

        if (!$newDate || !$newTime) {
            return;
        }

        $startDateTime = date('c', strtotime("{$newDate} {$newTime}"));
        $endDateTime = date('c', strtotime("{$newDate} {$newTime} +1 hour"));

        $service->updateEvent($demo->google_event_id, [
            'start' => $startDateTime,
            'end' => $endDateTime,
            'timeZone' => 'Asia/Kolkata',
        ]);

        Log::info("[GoogleCalendar] Rescheduled event {$demo->google_event_id} for demo {$demo->id}");
    }

    public function failed(Throwable $exception): void
    {
        Log::error("[GoogleCalendar] Job failed permanently for demo {$this->demoId}: " . $exception->getMessage());
        // Could send notification to admin here
    }
}
