<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\User\Repository;

use CpCreation\VitiCore\Repository\BaseRepository;
use CpCreation\VitiCore\User\Model\ImportedClientGroup;
use Doctrine\Persistence\ManagerRegistry;

class ImportedClientGroupRepository extends BaseRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, ImportedClientGroup::class);
    }

    public function findOneByEmail(string $email): ?ImportedClientGroup
    {
        return $this->createQueryBuilder('imported_client')
            ->addSelect('price_group')
            ->join('imported_client.group', 'price_group')
            ->andWhere('LOWER(imported_client.email) = :email')
            ->setParameter('email', mb_strtolower(mb_trim($email)))
            ->setMaxResults(1)
            ->getQuery()
            ->getOneOrNullResult();
    }

    /**
     * @return array{total: int, enabled: int, disabled: int}
     */
    public function getStatistics(): array
    {
        $row = $this->createQueryBuilder('imported_client')
            ->select('COUNT(imported_client.id) AS total')
            ->addSelect('SUM(CASE WHEN imported_client.applyOnRegistration = TRUE THEN 1 ELSE 0 END) AS enabled')
            ->getQuery()
            ->getSingleResult();

        $total = (int) ($row['total'] ?? 0);
        $enabled = (int) ($row['enabled'] ?? 0);

        return [
            'total' => $total,
            'enabled' => $enabled,
            'disabled' => $total - $enabled,
        ];
    }

    /**
     * @return list<array{group_name: string, total: int, enabled: int, disabled: int}>
     */
    public function getGroupDistribution(): array
    {
        $rows = $this->createQueryBuilder('imported_client')
            ->select('price_group.name AS group_name')
            ->addSelect('COUNT(imported_client.id) AS total')
            ->addSelect('SUM(CASE WHEN imported_client.applyOnRegistration = TRUE THEN 1 ELSE 0 END) AS enabled')
            ->join('imported_client.group', 'price_group')
            ->groupBy('price_group.id')
            ->addGroupBy('price_group.name')
            ->orderBy('price_group.name', 'ASC')
            ->getQuery()
            ->getArrayResult();

        return array_map(static function (array $row): array {
            $total = (int) ($row['total'] ?? 0);
            $enabled = (int) ($row['enabled'] ?? 0);

            return [
                'group_name' => (string) ($row['group_name'] ?? ''),
                'total' => $total,
                'enabled' => $enabled,
                'disabled' => $total - $enabled,
            ];
        }, $rows);
    }

    /**
     * @return list<ImportedClientGroup>
     */
    public function findByEmailOrder(?string $search = null): array
    {
        $queryBuilder = $this->createQueryBuilder('imported_client')
            ->addSelect('price_group')
            ->join('imported_client.group', 'price_group')
            ->orderBy('imported_client.email', 'ASC');

        if (null !== $search && '' !== mb_trim($search)) {
            $queryBuilder
                ->andWhere($queryBuilder->expr()->orX(
                    'LOWER(imported_client.email) LIKE :search',
                    'LOWER(price_group.name) LIKE :search',
                ))
                ->setParameter('search', '%' . mb_strtolower(mb_trim($search)) . '%');
        }

        return $queryBuilder->getQuery()->getResult();
    }

    /**
     * @param list<string> $emails
     *
     * @return array<string, ImportedClientGroup>
     */
    public function findIndexedByEmails(array $emails): array
    {
        $items = [];

        foreach (array_chunk(array_values(array_unique($emails)), 500) as $emailChunk) {
            $results = $this->createQueryBuilder('imported_client')
                ->addSelect('price_group')
                ->join('imported_client.group', 'price_group')
                ->andWhere('LOWER(imported_client.email) IN (:emails)')
                ->setParameter('emails', $emailChunk)
                ->getQuery()
                ->getResult();

            foreach ($results as $item) {
                if ($item instanceof ImportedClientGroup) {
                    $items[mb_strtolower($item->getEmail())] = $item;
                }
            }
        }

        return $items;
    }
}
