<?php

namespace App\Jobs;

use App\Models\Task;
use App\Models\TaskTag;
use App\Models\TaskProduct;
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\Log;

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

    public function __construct()
    {
        //
    }

    public function handle(): void
    {
        try {
            $currentDate = now();
            $today = $currentDate->format('Y-m-d');

            // Find all recurring tasks that haven't spawned a successor yet
            $recurringTasks = Task::where('type', 'recurring')
                ->where('interval', '!=', null)
                ->where('has_recurred', false)
                ->where('stop_recurrence', 0)
                ->where('is_deleted', false)
                ->get();

            foreach ($recurringTasks as $task) {
                $this->generateNextOccurrence($task, $today);
            }

            Log::info('Recurring tasks generation completed.');
        } catch (\Throwable $th) {
            Log::error('Failed to generate recurring tasks: ' . $th->getMessage());
        }
    }

    private function getBufferDays($interval)
    {
        return match($interval) {
            'daily' => 0,
            'weekly' => 2,
            'fortnightly' => 3,
            'monthly' => 5,
            'quarterly' => 5,
            'half_yearly' => 5,
            'yearly' => 5,
            default => 0,
        };
    }

    private function calculateNextDueDate($currentDueDate, $interval)
    {
        $date = \Carbon\Carbon::parse($currentDueDate);

        return match($interval) {
            'daily' => $date->addDay(),
            'weekly' => $date->addWeek(),
            'fortnightly' => $date->addWeeks(2),
            'monthly' => $date->addMonth(),
            'quarterly' => $date->addMonths(3),
            'half_yearly' => $date->addMonths(6),
            'yearly' => $date->addYear(),
            default => $date,
        };
    }

    private function generateNextOccurrence($originalTask, $today)
    {
        $nextStartDate = $this->calculateNextDueDate($originalTask->start_date, $originalTask->interval);
        $nextDueDate = $this->calculateNextDueDate($originalTask->due_date, $originalTask->interval);

        $buffer = $this->getBufferDays($originalTask->interval);

        // Calculate trigger date (next date - buffer days)
        $triggerDateObj = clone $nextDueDate;
        $triggerDateObj->subDays($buffer);
        $triggerDate = $triggerDateObj->format('Y-m-d');

        // Only create if today has reached the trigger date (allows catch-up)
        if ($today < $triggerDate) {
            return;
        }

        // Prevent duplication - check if task with same name, lead_id, and start_date already exists
        $existingTask = Task::where('name', $originalTask->name)
            ->where('lead_id', $originalTask->lead_id)
            ->where('start_date', $nextStartDate->format('Y-m-d'))
            ->where('is_deleted', false)
            ->first();

        if ($existingTask) {
            // Already exists, mark current as reoccurred and skip
            $originalTask->update(['has_recurred' => true]);
            Log::info("Task already exists for date {$nextStartDate->format('Y-m-d')}, marking task ID {$originalTask->id} as reoccurred");
            return;
        }

        $newTask = Task::create([
            'lead_id' => $originalTask->lead_id,
            'project_id' => $originalTask->project_id,
            'project_ticket_id' => $originalTask->project_ticket_id,
            'created_by' => $originalTask->created_by,
            'assigned_to' => $originalTask->assigned_to,
            'name' => $originalTask->name,
            'description' => $originalTask->description,
            'start_date' => $nextStartDate,
            'due_date' => $nextDueDate,
            'priority' => $originalTask->priority,
            'type' => $originalTask->type,
            'interval' => $originalTask->interval,
            'has_recurred' => false,
            'created_at' => now(),
        ]);

        // Copy tags
        $originalTags = TaskTag::where('task_id', $originalTask->id)->get();
        foreach ($originalTags as $tag) {
            TaskTag::create([
                'task_id' => $newTask->id,
                'tag_id' => $tag->tag_id,
                'created_at' => now(),
            ]);
        }

        // Copy products
        $originalProducts = TaskProduct::where('task_id', $originalTask->id)->get();
        foreach ($originalProducts as $product) {
            TaskProduct::create([
                'task_id' => $newTask->id,
                'product_id' => $product->product_id,
                'created_at' => now(),
            ]);
        }

        // Mark original task as having recurred
        $originalTask->update(['has_recurred' => true]);

        Log::info("Generated recurring task ID: {$newTask->id} from original task ID: {$originalTask->id}");
    }
}
