<?php

/**
 * Copyright 2024-2025 Simply.IN Sp. z o.o.
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the EUPL-1.2 or later.
 * You may not use this work except in compliance with the Licence.
 *
 * Copy of the Licence is available at:
 * https://joinup.ec.europa.eu/software/page/eupl
 * It is bundled with this package in the file LICENSE.txt
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Licence is distributed on an as is basis,
 * without warranties or conditions of any kind, either express or implied.
 * Check the Licence for the specific language governing permissions
 * and limitations under the License.
 *
 * @author   Simply.IN Sp. z o.o.
 * @copyright 2024-2025 Simply.IN Sp. z o.o.
 * @license   https://joinup.ec.europa.eu/software/page/eupl
 */

declare(strict_types=1);

namespace SimplyIn\BackOffice;

use Doctrine\DBAL\Query\QueryBuilder;
use Module;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\DataColumn;
use PrestaShop\PrestaShop\Core\Grid\Definition\GridDefinitionInterface;
use PrestaShop\PrestaShop\Core\Grid\Filter\Filter;
use PrestaShop\PrestaShop\Core\Search\SearchCriteriaInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Throwable;

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

class OrdersGridDecorator
{
    private const COLUMN_ID = 'simplyin_point_label';
    private const COLUMN_AFTER = 'payment';
    private const FILTER_PARAM = 'simplyin_point_filter';

    public function __construct(private readonly Module $module)
    {
    }

    /**
     * @param array<string, mixed> $params
     */
    public function modifyDefinition(array $params): void
    {
        $definition = $params['definition'] ?? null;
        if (!$definition instanceof GridDefinitionInterface) {
            return;
        }

        $column = (new DataColumn(self::COLUMN_ID))
            ->setName($this->module->l('Simply.IN'))
            ->setOptions(['field' => self::COLUMN_ID, 'sortable' => true]);

        $columns = $definition->getColumns();

        try {
            $columns->addAfter(self::COLUMN_AFTER, $column);
        } catch (Throwable) {
            $columns->add($column);
        }

        $filter = (new Filter(self::COLUMN_ID, TextType::class))
            ->setTypeOptions(['required' => false])
            ->setAssociatedColumn(self::COLUMN_ID);
        $definition->getFilters()->add($filter);
    }

    /**
     * @param array<string, mixed> $params
     */
    public function modifyQuery(array $params): void
    {
        $searchQb = $params['search_query_builder'] ?? null;
        if (!$searchQb instanceof QueryBuilder) {
            return;
        }

        $subselect = sprintf(
            '(SELECT sp.label FROM %ssimplyin_point sp WHERE sp.cart_id = o.id_cart ORDER BY sp.id_simplyin_point DESC LIMIT 1)',
            _DB_PREFIX_,
        );
        $searchQb->addSelect($subselect . ' AS ' . self::COLUMN_ID);

        $criteria = $params['search_criteria'] ?? null;
        if ($criteria instanceof SearchCriteriaInterface) {
            $this->applyFilter($criteria, $searchQb, $subselect, $params['count_query_builder'] ?? null);
            $this->applySort($criteria, $searchQb);
        }
    }

    private function applyFilter(
        SearchCriteriaInterface $criteria,
        QueryBuilder $searchQb,
        string $subselect,
        mixed $countQb,
    ): void {
        $filters = $criteria->getFilters();
        $value = $filters[self::COLUMN_ID] ?? null;
        if (!is_string($value) || $value === '') {
            return;
        }

        $param = ':' . self::FILTER_PARAM;
        $searchQb->andHaving(self::COLUMN_ID . ' LIKE ' . $param)
            ->setParameter(self::FILTER_PARAM, '%' . $value . '%');

        if ($countQb instanceof QueryBuilder) {
            $countQb->andWhere($subselect . ' LIKE ' . $param)
                ->setParameter(self::FILTER_PARAM, '%' . $value . '%');
        }
    }

    private function applySort(SearchCriteriaInterface $criteria, QueryBuilder $searchQb): void
    {
        if ($criteria->getOrderBy() !== self::COLUMN_ID) {
            return;
        }
        $way = strtoupper($criteria->getOrderWay()) === 'DESC' ? 'DESC' : 'ASC';
        $searchQb->orderBy(self::COLUMN_ID, $way);
    }
}
