<?php

declare(strict_types=1);

namespace App\Module\Core\Infrastructure\Doctrine;

use App\Module\Core\Domain\Entity\User;
use App\Module\Core\Domain\Repository\UserRepositoryInterface;
use App\Shared\Domain\Contract\UserInterface;
use DateTimeInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @extends ServiceEntityRepository<User>
 */
class DoctrineUserRepository extends ServiceEntityRepository implements UserRepositoryInterface
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, User::class);
    }

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

    /**
     * @param int[] $ids
     *
     * @return list<UserInterface>
     */
    public function findByIds(array $ids): array
    {
        if ([] === $ids) {
            return [];
        }

        return $this->createQueryBuilder('u')
            ->where('u.id IN (:ids)')
            ->setParameter('ids', $ids)
            ->getQuery()
            ->getResult()
        ;
    }

    /**
     * @return list<UserInterface>
     */
    public function findByRole(string $role): array
    {
        $conn = $this->getEntityManager()->getConnection();
        $sql  = 'SELECT id FROM "user" WHERE roles::text LIKE :role';
        $ids  = $conn->executeQuery($sql, ['role' => '%"'.$role.'"%'])->fetchFirstColumn();

        if ([] === $ids) {
            return [];
        }

        return $this->createQueryBuilder('u')
            ->where('u.id IN (:ids)')
            ->setParameter('ids', $ids)
            ->getQuery()
            ->getResult()
        ;
    }

    /**
     * Employees active on the given date (hired on/before it, not yet left).
     *
     * @return list<UserInterface>
     */
    public function findActiveEmployees(DateTimeInterface $date): array
    {
        $dateStr = $date->format('Y-m-d');

        return $this->createQueryBuilder('u')
            ->where('u.isEmployee = true')
            ->andWhere('u.hireDate IS NULL OR u.hireDate <= :date')
            ->andWhere('u.endDate IS NULL OR u.endDate >= :date')
            ->setParameter('date', $dateStr)
            ->orderBy('u.username', 'ASC')
            ->getQuery()
            ->getResult()
        ;
    }

    public function findOneByUsername(string $username): ?UserInterface
    {
        return $this->findOneBy(['username' => $username]);
    }
}
