<?php

declare(strict_types=1);

namespace App\Module\ProjectManagement\Infrastructure\Mcp\Tool\Task;

use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use App\Shared\Infrastructure\Mcp\Serializer;
use Mcp\Capability\Attribute\McpTool;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

#[McpTool(name: 'list-tasks', description: 'List tasks with optional filters by project, status, assignee, collaborator, priority, group, tags, and archive state. Returns max 100 results by default, use filters to narrow down.')]
class ListTasksTool
{
    public function __construct(
        private readonly TaskRepositoryInterface $taskRepository,
        private readonly Security $security,
    ) {}

    /**
     * @param int[] $tagIds IDs of the tags to filter by
     */
    public function __invoke(
        ?int $projectId = null,
        ?int $statusId = null,
        ?int $assigneeId = null,
        ?int $collaboratorId = null,
        ?int $priorityId = null,
        ?int $groupId = null,
        ?array $tagIds = null,
        bool $archived = false,
        int $limit = 100,
    ): string {
        if (!$this->security->isGranted('ROLE_USER')) {
            throw new AccessDeniedException('Access denied: ROLE_USER required.');
        }

        $limit = min($limit, 200);

        $qb = $this->taskRepository->createQueryBuilder('t')
            ->leftJoin('t.status', 's')->addSelect('s')
            ->leftJoin('t.priority', 'p')->addSelect('p')
            ->leftJoin('t.assignee', 'a')->addSelect('a')
            ->leftJoin('t.collaborators', 'collab')->addSelect('collab')
            ->leftJoin('t.project', 'pr')->addSelect('pr')
            ->leftJoin('t.effort', 'e')->addSelect('e')
            ->leftJoin('t.group', 'g')->addSelect('g')
            ->leftJoin('t.tags', 'tg')->addSelect('tg')
            ->where('t.archived = :archived')
            ->setParameter('archived', $archived)
            ->orderBy('t.id', 'DESC')
            ->setMaxResults($limit)
        ;

        if (null !== $projectId) {
            $qb->andWhere('pr.id = :projectId')->setParameter('projectId', $projectId);
        }
        if (null !== $statusId) {
            $qb->andWhere('s.id = :statusId')->setParameter('statusId', $statusId);
        }
        if (null !== $assigneeId) {
            $qb->andWhere('a.id = :assigneeId')->setParameter('assigneeId', $assigneeId);
        }
        if (null !== $collaboratorId) {
            $qb->andWhere('collab.id = :collaboratorId')->setParameter('collaboratorId', $collaboratorId);
        }
        if (null !== $priorityId) {
            $qb->andWhere('p.id = :priorityId')->setParameter('priorityId', $priorityId);
        }
        if (null !== $groupId) {
            $qb->andWhere('t.group = :groupId')->setParameter('groupId', $groupId);
        }

        $tasks = $qb->getQuery()->getResult();

        if (null !== $tagIds) {
            $tasks = array_filter($tasks, function ($task) use ($tagIds) {
                $taskTagIds = $task->getTags()->map(fn ($t) => $t->getId())->toArray();

                return !empty(array_intersect($tagIds, $taskTagIds));
            });
        }

        return json_encode(array_map(fn ($task) => [
            'id'            => $task->getId(),
            'number'        => $task->getNumber(),
            'title'         => $task->getTitle(),
            'status'        => Serializer::status($task->getStatus()),
            'priority'      => Serializer::priority($task->getPriority()),
            'assignee'      => Serializer::user($task->getAssignee()),
            'collaborators' => Serializer::users($task->getCollaborators()),
            'effort'        => Serializer::effort($task->getEffort()),
            'group'         => Serializer::groupRef($task->getGroup()),
            'project'       => Serializer::projectRef($task->getProject()),
            'tags'          => Serializer::tags($task->getTags()),
            'archived'      => $task->isArchived(),
        ], array_values($tasks)));
    }
}
