<?php

declare(strict_types=1);

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

use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Module\ProjectManagement\Domain\Entity\TaskStatus;
use App\Module\ProjectManagement\Infrastructure\Service\CalDavService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * @implements ProcessorInterface<Task, Task>
 */
final readonly class TaskCalendarProcessor implements ProcessorInterface
{
    /**
     * @param ProcessorInterface<Task, Task> $persistProcessor
     * @param ProcessorInterface<Task, Task> $removeProcessor
     */
    public function __construct(
        #[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')]
        private ProcessorInterface $persistProcessor,
        #[Autowire(service: 'api_platform.doctrine.orm.state.remove_processor')]
        private ProcessorInterface $removeProcessor,
        private CalDavService $calDavService,
        private EntityManagerInterface $entityManager,
        private RecurrenceHandler $recurrenceHandler,
    ) {}

    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
    {
        if ($operation instanceof Delete) {
            $eventUid = $data->getCalendarEventUid();
            $todoUid  = $data->getCalendarTodoUid();

            $result = $this->removeProcessor->process($data, $operation, $uriVariables, $context);

            if ($eventUid) {
                $this->calDavService->deleteEvent($eventUid);
            }
            if ($todoUid) {
                $this->calDavService->deleteTodo($todoUid);
            }

            return $result;
        }

        // Detect isFinal transition using Doctrine UnitOfWork.
        // $data already has the NEW values (API Platform deserialized the PATCH).
        // UnitOfWork originalEntityData stores the DB snapshot with entity references for relations.
        $uow             = $this->entityManager->getUnitOfWork();
        $originalData    = $uow->getOriginalEntityData($data);
        $wasAlreadyFinal = false;

        if (isset($originalData['status']) && $originalData['status'] instanceof TaskStatus) {
            $wasAlreadyFinal = $originalData['status']->getIsFinal();
        }

        $result = $this->persistProcessor->process($data, $operation, $uriVariables, $context);

        // Sync to Zimbra after DB flush
        $this->calDavService->syncTask($data);
        $this->entityManager->flush();

        // Check for recurrence auto-creation (only on STATUS CHANGE to isFinal)
        $this->recurrenceHandler->handleIfNeeded($data, $wasAlreadyFinal);

        return $result;
    }
}
