<?php

declare(strict_types=1);

namespace App\Module\ProjectManagement\Infrastructure\Doctrine;

use App\Module\ProjectManagement\Domain\Entity\Project;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @extends ServiceEntityRepository<Task>
 */
class DoctrineTaskRepository extends ServiceEntityRepository implements TaskRepositoryInterface
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Task::class);
    }

    public function findById(int $id): ?Task
    {
        return $this->find($id);
    }

    /**
     * Returns the max task number for a project, using an advisory lock
     * to prevent race conditions when creating tasks concurrently.
     */
    public function findMaxNumberByProjectForUpdate(Project $project): int
    {
        $conn = $this->getEntityManager()->getConnection();

        // Use PostgreSQL advisory lock (project ID as lock key) instead of FOR UPDATE
        // because FOR UPDATE is not allowed with aggregate functions in PostgreSQL.
        $conn->executeStatement(
            'SELECT pg_advisory_xact_lock(:project)',
            ['project' => $project->getId()],
        );

        $result = $conn->fetchOne(
            'SELECT COALESCE(MAX(number), 0) FROM task WHERE project_id = :project',
            ['project' => $project->getId()],
        );

        return (int) $result;
    }
}
