<?php
/**
 * Copyright since 2025 InPost S.A.
 *
 * For the full license information, please view the LICENSE file bundled with the module.
 *
 * @author InPost S.A.
 * @copyright since 2025 InPost S.A.
 * @license MIT
 */

declare(strict_types=1);

namespace InPost\International\PickupAddress\Grid;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Query\QueryBuilder;
use PrestaShop\PrestaShop\Core\Grid\Query\AbstractDoctrineQueryBuilder;
use PrestaShop\PrestaShop\Core\Grid\Query\DoctrineSearchCriteriaApplicatorInterface;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class PickupAddressQueryBuilder extends AbstractDoctrineQueryBuilder
{
    private const CONTACT_PERSON_EXPR = 'CONCAT(a.first_name, " ", a.last_name)';
    private const ADDRESS_EXPR = 'CONCAT(a.street, " ", a.house_number, COALESCE(CONCAT(" / ", a.flat_number), ""))';

    /**
     * @var DoctrineSearchCriteriaApplicatorInterface
     */
    private $searchCriteriaApplicator;

    public function __construct(Connection $connection, string $dbPrefix, DoctrineSearchCriteriaApplicatorInterface $searchCriteriaApplicator)
    {
        parent::__construct($connection, $dbPrefix);
        $this->searchCriteriaApplicator = $searchCriteriaApplicator;
    }

    public function getSearchQueryBuilder(SearchCriteriaInterface $searchCriteria): QueryBuilder
    {
        $queryBuilder = $this
            ->getCommonQueryBuilder($searchCriteria)
            ->select('a.id, a.name, a.is_default, a.postcode, a.city, a.country')
            ->addSelect(self::CONTACT_PERSON_EXPR . ' AS contact_person')
            ->addSelect(self::ADDRESS_EXPR . ' AS address');

        $this->searchCriteriaApplicator
            ->applyPagination($searchCriteria, $queryBuilder)
            ->applySorting($searchCriteria, $queryBuilder);

        return $queryBuilder;
    }

    public function getCountQueryBuilder(SearchCriteriaInterface $searchCriteria): QueryBuilder
    {
        return $this
            ->getCommonQueryBuilder($searchCriteria)
            ->select('COUNT(*)');
    }

    private function getCommonQueryBuilder(SearchCriteriaInterface $searchCriteria): QueryBuilder
    {
        $queryBuilder = $this->connection
            ->createQueryBuilder()
            ->from($this->dbPrefix . 'inpost_intl_pickup_address', 'a')
            ->andWhere('a.is_deleted = 0');

        $this->applyFilters($searchCriteria->getFilters(), $queryBuilder);

        return $queryBuilder;
    }

    /**
     * @param array<string, mixed> $filters
     */
    private function applyFilters(array $filters, QueryBuilder $qb): void
    {
        foreach ($filters as $filterName => $filterValue) {
            switch ($filterName) {
                case 'id':
                case 'country':
                    $qb->andWhere('a.' . $filterName . ' = :' . $filterName);
                    $qb->setParameter($filterName, $filterValue);

                    break;
                case 'name':
                case 'postcode':
                case 'city':
                    $qb->andWhere('a.' . $filterName . ' LIKE :' . $filterName);
                    $qb->setParameter($filterName, '%' . $filterValue . '%');

                    break;
                case 'is_default':
                    $qb->andWhere('a.is_default = :default');
                    $qb->setParameter('default', $filterValue, ParameterType::BOOLEAN);

                    break;
                case 'contact_person':
                    $qb->andWhere(self::CONTACT_PERSON_EXPR . ' LIKE :contactPerson');
                    $qb->setParameter('contactPerson', '%' . $filterValue . '%', ParameterType::STRING);

                    break;
                case 'address':
                    $qb->andWhere(self::ADDRESS_EXPR . ' LIKE :address');
                    $qb->setParameter('address', '%' . $filterValue . '%', ParameterType::STRING);

                    break;
                default:
                    break;
            }
        }
    }
}
