<?php

declare(strict_types=1);

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

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Module\Reporting\Application\DTO\TasksByStatusOutput;
use Doctrine\DBAL\Connection;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * Provider DBAL (lecture seule) du rapport taches-par-statut.
 *
 * N'importe AUCUNE entite : couplage au seul schema SQL physique. Le filtre
 * projectId est passe en bound param.
 *
 * @implements ProviderInterface<TasksByStatusOutput>
 */
final readonly class TasksByStatusProvider implements ProviderInterface
{
    use ReportFilterTrait;

    public function __construct(
        #[Autowire(service: 'doctrine.dbal.default_connection')]
        private Connection $connection,
    ) {}

    /**
     * @return list<TasksByStatusOutput>
     */
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
    {
        /** @var array<string, mixed> $filters */
        $filters = $context['filters'] ?? [];

        $projectId = $this->validatePositiveInt($filters['projectId'] ?? null, 'projectId');

        $qb = $this->connection->createQueryBuilder()
            ->select(
                's.id AS status_id',
                's.label AS status_label',
                'COUNT(t.id) AS cnt',
            )
            ->from('task', 't')
            ->leftJoin('t', 'task_status', 's', 't.status_id = s.id')
            ->where('t.archived = false')
            ->groupBy('s.id')
            ->addGroupBy('s.label')
            ->orderBy('cnt', 'DESC')
        ;

        if (null !== $projectId) {
            $qb->andWhere('t.project_id = :projectId')->setParameter('projectId', $projectId);
        }

        /** @var list<array<string, mixed>> $rows */
        $rows = $qb->executeQuery()->fetchAllAssociative();

        return array_map(static fn (array $row): TasksByStatusOutput => new TasksByStatusOutput(
            statusId: null !== $row['status_id'] ? (int) $row['status_id'] : null,
            statusLabel: null !== $row['status_label'] ? (string) $row['status_label'] : 'Sans statut',
            count: (int) $row['cnt'],
        ), $rows);
    }
}
