<?php

declare(strict_types=1);

namespace App\Repository;

use App\Entity\Employee;
use App\Entity\User;
use App\Repository\Contract\EmployeeScopedRepositoryInterface;
use App\Security\EmployeeScopeService;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @extends ServiceEntityRepository<Employee>
 */
final class EmployeeRepository extends ServiceEntityRepository implements EmployeeScopedRepositoryInterface
{
    public function __construct(
        ManagerRegistry $registry,
        private readonly EmployeeScopeService $employeeScopeService,
    ) {
        parent::__construct($registry, Employee::class);
    }

    /**
     * @param list<int> $employeeIds
     *
     * @return array<int, Employee>
     */
    public function findAccessibleByIds(array $employeeIds, User $user): array
    {
        if ([] === $employeeIds) {
            return [];
        }

        $qb = $this->createQueryBuilder('e')
            ->andWhere('e.id IN (:ids)')
            ->setParameter('ids', $employeeIds)
        ;

        $this->employeeScopeService->applyEmployeeScope($qb, 'e', 'employee_repo_scope', $user);

        /** @var list<Employee> $employees */
        $employees = $qb->getQuery()->getResult();

        $byId = [];
        foreach ($employees as $employee) {
            $employeeId = $employee->getId();
            if ($employeeId) {
                $byId[$employeeId] = $employee;
            }
        }

        return $byId;
    }

    /**
     * @return list<Employee>
     */
    public function findScoped(User $user): array
    {
        $qb = $this->createQueryBuilder('e')
            ->leftJoin('e.site', 's')
            ->addSelect('s')
            ->orderBy('s.name', 'ASC')
            ->addOrderBy('e.displayOrder', 'ASC')
            ->addOrderBy('e.lastName', 'ASC')
            ->addOrderBy('e.firstName', 'ASC')
        ;

        $this->employeeScopeService->applyEmployeeScope($qb, 'e', 'employee_scoped_list', $user);

        // @var list<Employee> $employees
        return $qb->getQuery()->getResult();
    }

    /**
     * @param list<int> $siteIds
     *
     * @return list<Employee>
     */
    public function findForPrintBySiteIds(array $siteIds): array
    {
        $qb = $this->createQueryBuilder('e')
            ->leftJoin('e.site', 's')
            ->addSelect('s')
            ->leftJoin('e.contract', 'c')
            ->addSelect('c')
            // Eager-load des périodes pour le filtre d'intersection contrat/période (impression),
            // évite un N+1 sur getContractPeriods() lors du filtrage des employés.
            ->leftJoin('e.contractPeriods', 'cp')
            ->addSelect('cp')
            ->orderBy('s.name', 'ASC')
            ->addOrderBy('e.displayOrder', 'ASC')
            ->addOrderBy('e.lastName', 'ASC')
            ->addOrderBy('e.firstName', 'ASC')
        ;

        if ([] !== $siteIds) {
            $qb->andWhere('s.id IN (:siteIds)')
                ->setParameter('siteIds', $siteIds)
            ;
        }

        // @var list<Employee> $employees
        return $qb->getQuery()->getResult();
    }
}
