<?php

declare(strict_types=1);

namespace App\Module\ProjectManagement\Infrastructure\ApiPlatform\State;

use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use App\Module\ProjectManagement\Domain\Repository\TaskStatusRepositoryInterface;
use App\Module\ProjectManagement\Infrastructure\Service\CalDavService;
use App\Module\ProjectManagement\Infrastructure\Service\RecurrenceCalculator;
use Doctrine\ORM\EntityManagerInterface;

final readonly class RecurrenceHandler
{
    public function __construct(
        private RecurrenceCalculator $calculator,
        private TaskRepositoryInterface $taskRepository,
        private TaskStatusRepositoryInterface $statusRepository,
        private CalDavService $calDavService,
        private EntityManagerInterface $entityManager,
    ) {}

    public function handleIfNeeded(Task $task, bool $wasAlreadyFinal): void
    {
        // Only trigger on STATUS CHANGE to isFinal
        $currentStatus = $task->getStatus();
        $isNowFinal    = $currentStatus?->getIsFinal() ?? false;

        if (!$isNowFinal || $wasAlreadyFinal) {
            return; // No transition to final
        }

        $recurrence = $task->getRecurrence();
        if (null === $recurrence) {
            return; // Not a recurring task
        }

        if ($this->calculator->hasReachedEnd($recurrence)) {
            return; // Recurrence is done
        }

        $nextStart = $this->calculator->getNextDate($task);
        if (null === $nextStart) {
            return;
        }

        // Archive current task, clear calendar UIDs
        $savedEventUid = $task->getCalendarEventUid();
        $task->setArchived(true);
        $task->setCalendarEventUid(null);
        $task->setCalendarTodoUid(null);

        // Create new task with same fields
        $newTask = new Task();
        $newTask->setProject($task->getProject());
        $newTask->setTitle($task->getTitle());
        $newTask->setDescription($task->getDescription());
        $newTask->setAssignee($task->getAssignee());
        $newTask->setEffort($task->getEffort());
        $newTask->setPriority($task->getPriority());
        $newTask->setGroup($task->getGroup());
        $newTask->setRecurrence($recurrence);
        $newTask->setSyncToCalendar($task->isSyncToCalendar());

        // Copy tags
        foreach ($task->getTags() as $tag) {
            $newTask->addTag($tag);
        }

        // Set first non-final status
        $firstStatus = $this->statusRepository->findFirstNonFinal();
        $newTask->setStatus($firstStatus);

        // Set recalculated dates
        $newTask->setScheduledStart($nextStart);
        $newTask->setScheduledEnd($this->calculator->getNextEnd($task, $nextStart));
        $newTask->setDeadline($this->calculator->getNextDeadline($task, $nextStart));

        // Copy calendar event UID (recurring VEVENT is shared)
        $newTask->setCalendarEventUid($savedEventUid);

        // Generate task number in transaction
        $project = $newTask->getProject();
        if (null === $project) {
            return;
        }
        $this->entityManager->wrapInTransaction(function () use ($newTask, $project): void {
            $maxNumber = $this->taskRepository->findMaxNumberByProjectForUpdate($project);
            $newTask->setNumber($maxNumber + 1);
            $this->entityManager->persist($newTask);
            $this->entityManager->flush();
        });

        // Increment occurrence count (with optimistic locking via @Version)
        $recurrence->incrementOccurrenceCount();
        $this->entityManager->flush();

        // Sync new task's VTODO (new deadline) to Zimbra
        if ($newTask->isSyncToCalendar() && $newTask->getDeadline()) {
            $uid = $this->calDavService->createTodo($newTask);
            if ($uid) {
                $newTask->setCalendarTodoUid($uid);
                $newTask->setCalendarSyncError(null);
                $this->entityManager->flush();
            }
        }
    }
}
