<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Marketing\Repository;

use CpCreation\VitiCore\Marketing\Model\AbandonedCartReminder;
use CpCreation\VitiCore\Marketing\Model\AbandonedCartRule;
use CpCreation\VitiCore\Repository\BaseRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;

final class AbandonedCartReminderRepository extends BaseRepository
{
    /** @throws \ReflectionException */
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, AbandonedCartReminder::class);
    }

    public function findOneByToken(string $token): ?AbandonedCartReminder
    {
        return $this->createQueryBuilder('reminder')
            ->addSelect('cart', 'rule', 'promo')
            ->innerJoin('reminder.cart', 'cart')
            ->innerJoin('reminder.rule', 'rule')
            ->leftJoin('reminder.promo', 'promo')
            ->andWhere('reminder.tokenHash = :tokenHash')
            ->setParameter('tokenHash', hash('sha256', $token))
            ->getQuery()
            ->getOneOrNullResult();
    }

    public function createAdminQueryBuilder(
        ?string $search = null,
        ?string $status = null,
        ?string $ruleId = null,
    ): QueryBuilder {
        $queryBuilder = $this->createQueryBuilder('reminder')
            ->addSelect('cart', 'rule', 'promo')
            ->innerJoin('reminder.cart', 'cart')
            ->innerJoin('reminder.rule', 'rule')
            ->leftJoin('reminder.promo', 'promo')
            ->orderBy('reminder.scheduledAt', 'DESC');

        $search = null !== $search ? mb_strtolower(mb_trim($search)) : '';
        if ('' !== $search) {
            $queryBuilder
                ->andWhere(<<<'DQL'
                    LOWER(reminder.recipientEmail) LIKE :reminderSearch
                    OR LOWER(COALESCE(cart.token, '')) LIKE :reminderSearch
                    OR LOWER(rule.name) LIKE :reminderSearch
                    OR LOWER(COALESCE(promo.title, '')) LIKE :reminderSearch
                    DQL)
                ->setParameter('reminderSearch', '%' . $search . '%');
        }

        if (null !== $status && \in_array($status, AbandonedCartReminder::STATUSES, true)) {
            $queryBuilder
                ->andWhere('reminder.status = :reminderStatus')
                ->setParameter('reminderStatus', $status);
        }

        if (null !== $ruleId) {
            $queryBuilder
                ->andWhere('rule.id = :reminderRuleId')
                ->setParameter('reminderRuleId', $ruleId);
        }

        return $queryBuilder;
    }

    public function countForRule(AbandonedCartRule $rule): int
    {
        return (int) $this->createQueryBuilder('reminder')
            ->select('COUNT(reminder.id)')
            ->andWhere('reminder.rule = :rule')
            ->setParameter('rule', $rule)
            ->getQuery()
            ->getSingleScalarResult();
    }
}
