<?php

declare(strict_types=1);

namespace App\State;

use ApiPlatform\Metadata\DeleteOperationInterface;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Entity\Employee;
use App\Entity\EmployeeWeekComment;
use App\Service\AuditLogger;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;

final readonly class EmployeeWeekCommentWriteProcessor implements ProcessorInterface
{
    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 EntityManagerInterface $entityManager,
        private AuditLogger $auditLogger,
    ) {}

    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
    {
        if (!$data instanceof EmployeeWeekComment) {
            return $data;
        }

        $employee = $data->getEmployee();

        if ($operation instanceof DeleteOperationInterface) {
            $this->auditLogger->log(
                $employee,
                'delete',
                'week_comment',
                $data->getId(),
                sprintf('Commentaire semaine supprimé pour %s (semaine du %s)', $this->label($employee), $data->getWeekStartDate()?->format('d/m/Y') ?? '?'),
                ['old' => ['content' => $data->getContent()]],
                $data->getWeekStartDate(),
            );
            $result = $this->removeProcessor->process($data, $operation, $uriVariables, $context);
            $this->entityManager->flush();

            return $result;
        }

        $weekStart = $data->getWeekStartDate();
        if (null === $weekStart || '1' !== $weekStart->format('N')) {
            throw new UnprocessableEntityHttpException('weekStartDate must be a Monday (ISO weekday 1).');
        }

        $prev = null;
        if (null !== $data->getId()) {
            $prev = $this->entityManager->getUnitOfWork()->getOriginalEntityData($data)['content'] ?? null;
            $data->touchUpdatedAt();
        }

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

        if (null === $prev) {
            $this->auditLogger->log($employee, 'create', 'week_comment', $data->getId(), sprintf('Commentaire semaine créé pour %s (semaine du %s)', $this->label($employee), $weekStart->format('d/m/Y')), ['new' => ['content' => $data->getContent()]], $weekStart);
        } elseif ($prev !== $data->getContent()) {
            $this->auditLogger->log($employee, 'update', 'week_comment', $data->getId(), sprintf('Commentaire semaine modifié pour %s (semaine du %s)', $this->label($employee), $weekStart->format('d/m/Y')), ['old' => ['content' => $prev], 'new' => ['content' => $data->getContent()]], $weekStart);
        }

        $this->entityManager->flush();

        return $result;
    }

    private function label(mixed $e): string
    {
        return $e instanceof Employee ? trim(($e->getLastName() ?? '').' '.($e->getFirstName() ?? '')) : '?';
    }
}
