<?php

namespace Myvetshop\Module\Clinique\Adapter\Recommandation;

use Myvetshop\Module\Clinique\Entity\Recommandation;
use Myvetshop\Module\Clinique\Entity\RecommandationProduct;

class RecommandationCartRuleRepository
{
    private \Db $db;

    /**
     * @var list<string>
     */
    private array $allowedManufacturers = [
        'HILL\'S PET NUTRITION',
        'NPPCOF NESTLE PURINA PET CARE',
        'PRO PLAN',
        'ROYAL CANIN',
        'VIRBAC FRANCE',
        'VIRBAC NUTRITION',
    ];

    protected function queryToCartRule(string $query): ?\CartRule
    {
        $cartRuleId = (int) $this->db->getValue($query);

        $cartRule = new \CartRule($cartRuleId);

        if (\Validate::isLoadedObject($cartRule)) {
            return $cartRule;
        }

        return null;
    }

    public function __construct(
        \Db $db
    ) {
        $this->db = $db;
    }

    public function createCartRule(Recommandation $recommandation): ?\CartRule
    {
        $cartRule = $this->getCartRule($recommandation);
        if ($cartRule) {
            return $cartRule;
        }

        // Isole les produits autorisés à recevoir à bon de réduction
        $allowedManufacturers = \implode(
            ',',
            \array_map(
                fn (string $manufacturer) => '"' . $this->db->escape($manufacturer) . '"',
                $this->allowedManufacturers
            )
        );
        $productsIds = \implode(
            ',',
            \array_map(
                fn (RecommandationProduct $product) => (int) $product->idProduct,
                $recommandation->getProduits()->toArray(),
            )
        );

        $query = 'SELECT p.id_product FROM ' . _DB_PREFIX_ . 'product p'
            . ' INNER JOIN ' . _DB_PREFIX_ . 'manufacturer m ON p.id_manufacturer = m.id_manufacturer'
            . ' WHERE p.id_product IN (' . $productsIds . ')'
            . ' AND m.name IN (' . $allowedManufacturers . ')';
        $rows = $this->db->executeS($query);

        if (!\is_array($rows)) {
            throw new \Exception('Impossible de récupérer la liste des produits');
        }

        /** @var list<int> $allowedProductIds */
        $allowedProductIds = \array_map(
            fn (array $row) => (int) $row['id_product'],
            $rows,
        );

        // Aucun produit compatible avec un bon de réduction
        if (empty($allowedProductIds)) {
            return null;
        }

        $cartRule = new \CartRule();
        $cartRule->id_customer = $recommandation->idCustomer;
        $cartRule->code = $recommandation->codeReco;
        $cartRule->quantity = 1;
        $cartRule->quantity_per_user = 1;
        $cartRule->product_restriction = true;
        $cartRule->reduction_percent = 10.00;
        $cartRule->highlight = true;
        // sélection de produits
        $cartRule->reduction_product = -2;
        $cartRule->date_from = \date('Y-m-d H:i:s');
        $cartRule->date_to = (new \DateTime('+1 year'))->format('Y-m-d H:i:s');
        $cartRule->active = true;

        /** @var int[] $idLangs */
        $idLangs = \Language::getLanguages(true, false, true);
        foreach ($idLangs as $idLang) {
            $cartRule->name[$idLang] = 'Remise recommandation Crokit ' . $cartRule->code;
        }

        $cartRule->save();

        // Création du rule_group
        $query = 'INSERT INTO ' . _DB_PREFIX_ . 'cart_rule_product_rule_group (id_cart_rule, quantity)'
            . ' VALUES (' . (int) $cartRule->id . ', 1)';
        $this->db->execute($query);

        $groupId = (int) $this->db->Insert_ID();

        // Creation du product_rule
        $query = 'INSERT INTO ' . _DB_PREFIX_ . 'cart_rule_product_rule (id_product_rule_group, type)'
            . ' VALUES (' . $groupId . ', "products")';
        $this->db->execute($query);
        $productRuleId = (int) $this->db->Insert_ID();

        // Ajout de la restriction produit (uniquement les produits de la recommandation)
        $values = \implode(
            ',',
            \array_map(
                fn (int $productId) => '(' . $productRuleId . ', ' . $productId . ')',
                $allowedProductIds
            )
        );
        $query = 'INSERT INTO ' . _DB_PREFIX_ . 'cart_rule_product_rule_value (id_product_rule, id_item)'
            . ' VALUES ' . $values;
        $this->db->execute($query);

        return $cartRule;
    }

    public function getCartRule(Recommandation $recommandation): ?\CartRule
    {
        $query = 'SELECT id_cart_rule FROM `' . _DB_PREFIX_ . 'cart_rule` AS cart_rule'
            . ' WHERE cart_rule.code = "' . $this->db->escape($recommandation->codeReco) . '"';

        return $this->queryToCartRule($query);
    }

    public function getCartRuleForCustomerAndProduct(\Customer $customer, \Product $product): ?\CartRule
    {
        return $this->getCartRuleForCustomerAndProducts($customer, [(int) $product->id]);
    }

    /**
     * @param list<int|string> $productIds
     */
    public function getCartRuleForCustomerAndProducts(\Customer $customer, array $productIds): ?\CartRule
    {
        $query = 'SELECT cr.id_cart_rule FROM ' . _DB_PREFIX_ . 'recommandation r'
            . ' INNER JOIN ' . _DB_PREFIX_ . 'cart_rule cr ON cr.code = r.code_reco'
            . ' INNER JOIN ' . _DB_PREFIX_ . 'cart_rule_product_rule_group crprg ON crprg.id_cart_rule = cr.id_cart_rule'
            . ' INNER JOIN ' . _DB_PREFIX_ . 'cart_rule_product_rule crpr ON crpr.id_product_rule_group = crprg.id_product_rule_group'
            . ' INNER JOIN ' . _DB_PREFIX_ . 'cart_rule_product_rule_value crprv ON crprv.id_product_rule = crpr.id_product_rule'
            . ' WHERE r.id_customer = ' . (int) $customer->id
            . ' AND cr.quantity > 0 AND cr.active = 1 AND date_to > NOW()'
            . ' AND crprv.id_item IN (' . \implode(',', \array_map(fn ($id) => \intval($id), $productIds)) . ')';

        return $this->queryToCartRule($query);
    }
}
