<?php

declare(strict_types=1);

namespace App\Module\Mail\Infrastructure\Controller;

use App\Module\Core\Domain\Entity\User;
use App\Module\Mail\Domain\Entity\TaskMailLink;
use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface;
use App\Module\Mail\Infrastructure\Security\MailAccessChecker;
use App\Module\ProjectManagement\Domain\Entity\Project;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Module\ProjectManagement\Domain\Entity\TaskGroup;
use App\Module\ProjectManagement\Domain\Entity\TaskStatus;
use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

#[Route('/api/mail/messages/{id}/create-task', name: 'mail_create_task', methods: ['POST'], priority: 1, requirements: ['id' => '\d+'])]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class MailCreateTaskController extends AbstractController
{
    public function __construct(
        private readonly MailMessageRepositoryInterface $messageRepository,
        private readonly EntityManagerInterface $em,
        private readonly MailAccessChecker $accessChecker,
        private readonly TaskRepositoryInterface $taskRepository,
    ) {}

    public function __invoke(Request $request, int $id): JsonResponse
    {
        $this->accessChecker->ensureCanAccessMail($this->getUser());

        $message = $this->messageRepository->findById($id);
        if (null === $message) {
            throw new NotFoundHttpException('Message not found');
        }

        $body      = json_decode($request->getContent(), true);
        $projectId = $body['projectId'] ?? null;

        if (null === $projectId) {
            throw new UnprocessableEntityHttpException('projectId is required');
        }

        $project = $this->em->getRepository(Project::class)->find($projectId);
        if (null === $project) {
            throw new NotFoundHttpException('Project not found');
        }

        $title = $message->getSubject() ?? 'Mail sans sujet';
        if (mb_strlen($title) > 255) {
            $title = mb_substr($title, 0, 252).'...';
        }

        $result = $this->em->wrapInTransaction(function () use ($project, $title, $body, $message) {
            $maxNumber = $this->taskRepository->findMaxNumberByProjectForUpdate($project);

            $task = new Task();
            $task->setProject($project);
            $task->setTitle($title);
            $task->setNumber($maxNumber + 1);

            if (isset($body['taskGroupId']) && null !== $body['taskGroupId']) {
                $taskGroup = $this->em->getRepository(TaskGroup::class)->find($body['taskGroupId']);
                if (null !== $taskGroup) {
                    $task->setGroup($taskGroup);
                }
            }

            if (isset($body['assigneeId']) && null !== $body['assigneeId']) {
                $assignee = $this->em->getRepository(User::class)->find($body['assigneeId']);
                if (null !== $assignee) {
                    $task->setAssignee($assignee);
                }
            }

            // Statut : celui fourni, sinon le premier statut du workflow du projet (par position)
            $status = null;
            if (isset($body['statusId']) && null !== $body['statusId']) {
                $status = $this->em->getRepository(TaskStatus::class)->find($body['statusId']);
            }
            if (null === $status) {
                $status = $project->getWorkflow()?->getStatuses()->first() ?: null;
            }
            if (null !== $status) {
                $task->setStatus($status);
            }

            $this->em->persist($task);

            $link = new TaskMailLink();
            $link->setTask($task);
            $link->setMailMessage($message);
            $link->setLinkedAt(new DateTimeImmutable());
            $link->setLinkedBy($this->getUser());
            $this->em->persist($link);

            $this->em->flush();

            return $task;
        });

        return $this->json([
            'taskId'     => $result->getId(),
            'taskNumber' => $result->getNumber(),
            'taskTitle'  => $result->getTitle(),
            'messageId'  => $message->getId(),
        ], 201);
    }
}
