<?php

declare(strict_types=1);

class Recommandation extends ObjectModel
{
    public const TABLE = 'recommandation';

    /**
     * @var int
     */
    public $id_customer;

    /**
     * @var int
     */
    public $id_animal;

    public $id_recommandation_product;

    /**
     * @var string
     */
    public $code_reco;

    /**
     * @var string
     */
    public $date_reco;

    /**
     * @var string
     */
    public $code_clinique;

    /**
     * @var string
     */
    public $petname;

    /**
     * @var string
     */
    public $espece;

    /**
     * @var string
     */
    public $race;

    /**
     * @var int
     */
    public $id_gender;

    /**
     * @var string
     */
    public $activite;

    /**
     * @var string
     */
    public $age;

    /**
     * @var string
     */
    public $date_birth;

    /**
     * @var string
     */
    public $stade_physio;

    /**
     * @var string
     */
    public $pathologie;

    /** @var float */
    public $poids_actuel;

    /** @var float */
    public $poids_ideal;

    /** @var int */
    public $be;

    /** @var int */
    public $nbr_aliment;

    /** @var int */
    public $product_id_mvs1;

    /** @var int|null */
    public $product_id_mvs2;

    /** @var int|null */
    public $product_id_mvs3;

    /** @var int */
    public $qte_aliment1;

    /** @var int|null */
    public $qte_aliment2;

    /** @var int|null */
    public $qte_aliment3;

    /** @var int|null Nombre de mois avant la transition entre l'aliment 1 et l'aliment 2 */
    public $transition12;

    /** @var int|null Nombre de mois avant la transition entre l'aliment 2 et l'aliment 3 */
    public $transition23;

    /** @var string|null Object creation date */
    public $date_add;

    /** @var string|null Object last modification date */
    public $date_upd;

    /** @var bool */
    public $deleted = false;

    /**
     * @var array<string, mixed>
     */
    public static $definition = [
        'table' => self::TABLE,
        'primary' => 'id_recommandation',
        'multilang' => false,
        'multilang_shop' => false,
        'fields' => [
            'id_customer' => ['type' => self::TYPE_INT],
            'id_animal' => ['type' => self::TYPE_INT],
            'code_reco' => ['type' => self::TYPE_STRING],
            'date_reco' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'],
            'code_clinique' => ['type' => self::TYPE_STRING],
            'petname' => ['type' => self::TYPE_STRING],
            'espece' => ['type' => self::TYPE_STRING],
            'race' => ['type' => self::TYPE_STRING],
            'id_gender' => ['type' => self::TYPE_INT],
            'activite' => ['type' => self::TYPE_STRING],
            'age' => ['type' => self::TYPE_STRING],
            'date_birth' => ['type' => self::TYPE_STRING],
            'stade_physio' => ['type' => self::TYPE_STRING],
            'pathologie' => ['type' => self::TYPE_STRING],
            'poids_actuel' => ['type' => self::TYPE_FLOAT],
            'poids_ideal' => ['type' => self::TYPE_FLOAT],
            'be' => ['type' => self::TYPE_INT],
            'nbr_aliment' => ['type' => self::TYPE_INT],

            'id_recommandation_product' => ['type' => self::TYPE_INT],

            'product_id_mvs1' => ['type' => self::TYPE_INT],
            'product_id_mvs2' => ['type' => self::TYPE_INT],
            'product_id_mvs3' => ['type' => self::TYPE_INT],
            'qte_aliment1' => ['type' => self::TYPE_INT],
            'qte_aliment2' => ['type' => self::TYPE_INT],
            'qte_aliment3' => ['type' => self::TYPE_INT],
            'transition12' => ['type' => self::TYPE_INT],
            'transition23' => ['type' => self::TYPE_INT],

            'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false],
            'date_upd' => ['type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false],
            'deleted' => ['type' => self::TYPE_BOOL],
        ],
    ];

    public function update($auto_date = true, $null_values = false)
    {
        $recommandation = parent::update($auto_date, $null_values);

        if ($this->code_reco && !$this->hasCartRule()) {
            $cartRule = new CartRule();
            $cartRule->code = $this->code_reco;
            $cartRule->quantity = 1;
            $cartRule->quantity_per_user = 1;
            $cartRule->product_restriction = 1;
            $cartRule->reduction_percent = 5.00;
            // sélection poduits
            $cartRule->reduction_product = -2;
            $cartRule->date_from = (new DateTime())->format('Y-m-d H:i:s');
            $cartRule->date_to = (new DateTime())->add(new DateInterval('P1Y'))->format('Y-m-d H:i:s');
            $cartRule->active = true;

            foreach (Language::getLanguages() as $lang) {
                $cartRule->name[$lang['id_lang']] = 'Remise recommandation';
            }

            $cartRule->save();

            //Creating rule group
            $query = 'INSERT INTO ' . _DB_PREFIX_ . "cart_rule_product_rule_group (id_cart_rule, quantity) VALUES ('$cartRule->id', 1)";
            Db::getInstance()->execute($query);

            $groupId = (int) Db::getInstance()->Insert_ID();

            //Creating product rule
            $query = 'INSERT INTO ' . _DB_PREFIX_ . "cart_rule_product_rule (id_product_rule_group, type) VALUES ('$groupId', 'products')";
            Db::getInstance()->execute($query);
            $productRuleId = (int) Db::getInstance()->Insert_ID();

            //Creating restrictions
            foreach ($this->getProducts() as $recommandationProduct) {
                $query = 'INSERT INTO ' . _DB_PREFIX_ . 'cart_rule_product_rule_value (id_product_rule, id_item) VALUES (' . $productRuleId . ', ' . $recommandationProduct->id_product . ')';
                Db::getInstance()->execute($query);
            }
        }

        return $recommandation;
    }

    public function hasCartRule(): bool
    {
        return !is_null($this->getCartRule());
    }

    public function getCartRule(): ?CartRule
    {
        $query = 'SELECT id_cart_rule FROM `' . _DB_PREFIX_ . 'cart_rule`  AS cart_rule WHERE cart_rule.code = "' . Db::getInstance()->escape($this->code_reco) . '"';
        $cartRuleId = Db::getInstance()->getValue($query);

        $cartRule = new CartRule($cartRuleId);

        return Validate::isLoadedObject($cartRule) ? $cartRule : null;
    }

    public function getAnimal(): Animal
    {
        return new Animal($this->id_animal);
    }

    public function hasCustomer(int $customerId): bool
    {
        return $this->id_customer == $customerId;
    }

    /**
     * @return MyvetshopRecommandationProduct[]
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function getProducts(): array
    {
        return MyvetshopRecommandationProduct::getByRecommandationId((int) $this->id);
    }

    public function getCurrentProduct(): ?MyvetshopRecommandationProduct
    {
        $recommandationProduct = new MyvetshopRecommandationProduct($this->id_recommandation_product);

        return Validate::isLoadedObject($recommandationProduct) ? $recommandationProduct : null;
    }

    /**
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function createDiscountCode(): void
    {
        if (!$this->code_reco) {
            throw new Exception('La recommandation doit avoir un code reco');
        }

        // check si reduction avec ce code existe
        $db = Db::getInstance();

        $query = 'SELECT COUNT(id_cart_rule) AS numberOfCode FROM `' . _DB_PREFIX_ . 'cart_rule`  AS cart_rule WHERE cart_rule.code = "' . $db->escape($this->code_reco) . '"';
        $result = $db->executeS($query);

        if (is_array($result) and isset($result[0]) and isset($result[0]['numberOfCode']) and $result[0]['numberOfCode'] > 0) {
            return;
        }

        $productsId = [];

        $this->product_id_mvs1 ? array_push($productsId, $this->product_id_mvs1) : null;
        $this->product_id_mvs2 ? array_push($productsId, $this->product_id_mvs2) : null;
        $this->product_id_mvs3 ? array_push($productsId, $this->product_id_mvs3) : null;

        $now = new DateTime();

        $cartRule = new CartRule();
        $cartRule->name[1] = 'Remise recommandation';

        $cartRule->code = $this->code_reco;

        $cartRule->quantity = 1;
        $cartRule->quantity_per_user = 1;
        $cartRule->product_restriction = 1;
        $cartRule->reduction_percent = 5.00;

        // sélection poduits
        $cartRule->reduction_product = -2;

        $cartRule->date_from = $now->format('Y-m-d H:i:s');
        $dateTo = date_modify($now, '+1 year');

        if (!$dateTo instanceof DateTime) {
            throw new Exception('La date doit être un objet Datetime');
        }

        $cartRule->date_to = $dateTo->format('Y-m-d H:i:s');
        $cartRule->active = 1;

        $cartRule->save();

        //Creating rule group
        $id_cart_rule = (int) $cartRule->id;
        $sql = 'INSERT INTO ' . _DB_PREFIX_ . "cart_rule_product_rule_group (id_cart_rule, quantity) VALUES ('$id_cart_rule', 1)";
        Db::getInstance()->execute($sql);
        $id_group = (int) Db::getInstance()->Insert_ID();

        //Creating product rule
        $sql = 'INSERT INTO ' . _DB_PREFIX_ . "cart_rule_product_rule (id_product_rule_group, type) VALUES ('$id_group', 'products')";
        Db::getInstance()->execute($sql);
        $id_product_rule = (int) Db::getInstance()->Insert_ID();

        //Creating restrictions
        $values = [];
        foreach ($productsId as $id) {
            $id = (int) $id;
            $values[] = "('$id_product_rule', '$id')";
        }
        $values = implode(',', $values);
        $sql = 'INSERT INTO ' . _DB_PREFIX_ . 'cart_rule_product_rule_value (id_product_rule, id_item) VALUES ' . $values;
        Db::getInstance()->execute($sql);
    }

    /**
     * @return array<string, mixed>|null
     */
    public function getRecoProductByIdProduct(int $id_product): ?array
    {
        $db = Db::getInstance(false);

        $result = $db->getRow(
            'SELECT `p`.*, `pl`.*
             FROM `' . _DB_PREFIX_ . 'product_shop` `p`
             LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` `pl` ON `pl`.`id_product` = `p`.`id_product` AND `pl`.`id_lang` = ' . (int) Context::getContext()->language->id
            . ' WHERE `p`.`id_product` = ' . (int) $id_product
            . ' AND `p`.`id_shop` = ' . (int) Context::getContext()->shop->id
        );

        if (is_array($result)) {
            return $result;
        }

        return null;
    }

    public function getRecoProductImageIdByIdProduct(int $id_product): ?int
    {
        $db = Db::getInstance(false);

        $result = $db->getValue(
            'SELECT `i`.*
             FROM `' . _DB_PREFIX_ . 'image` `i`
             WHERE `i`.`id_product` = ' . (int) $id_product . ' AND `i`.`cover` = 1'
        );

        if (!$result) {
            return null;
        }

        return (int) $result;
    }

    public static function getByAnimalId(int $animalId): ?Recommandation
    {
        $query = 'SELECT MAX(id_recommandation) FROM ' . _DB_PREFIX_ . self::$definition['table'] . ' WHERE id_animal= ' . (int) $animalId . ' AND deleted = 0';
        $recommandationId = Db::getInstance()->getValue($query);

        return $recommandationId ? new Recommandation($recommandationId) : null;
    }

    /**
     * @param int $customerId
     *
     * @return Recommandation[]
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public static function getByCustomerId(int $customerId): array
    {
        $query = 'SELECT id_recommandation FROM ' . _DB_PREFIX_ . self::$definition['table'] . ' r 
                  INNER JOIN ' . _DB_PREFIX_ . Animal::$definition['table'] . ' a ON r.id_animal = a.id_animal
                  WHERE a.id_customer=' . $customerId . ' AND r.deleted=0 AND a.deleted=0';

        $list = array_column(Db::getInstance()->executeS($query), 'id_recommandation');

        return array_map(function ($recommandationId) {
            return new self($recommandationId);
        }, $list);
    }

    public static function codeExist(string $code): bool
    {
        $query = 'SELECT  COUNT(id_recommandation)
             FROM `' . _DB_PREFIX_ . self::$definition['table'] . '` `r`
             WHERE `r`.`deleted` = 0 AND `r`.`code_reco` = "' . Db::getInstance()->escape($code) . '"';

        return Db::getInstance()->getValue($query) > 0;
    }

    public static function customerHasCode(int $customerId, string $code): bool
    {
        $query = 'SELECT COUNT(id_recommandation)
             FROM `' . _DB_PREFIX_ . 'recommandation` `r`
             WHERE `r`.`id_customer` = ' . $customerId . ' AND `r`.`deleted` = 0 AND `r`.`code_reco` = "' . Db::getInstance()->escape($code) . '"';

        return Db::getInstance()->getValue($query) > 0;
    }

    public static function install(): bool
    {
        $query = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . static::TABLE . '` (
			  `id_recommandation` INT(11) NOT NULL AUTO_INCREMENT,
			  `id_customer` INT(11) NOT NULL,
              `id_animal` INT(11) NULL,
              `id_recommandation_product` INT(11) NULL,
              `code_reco` VARCHAR(6) NULL,
              `date_reco` DATETIME NOT NULL,
              `code_clinique` INT(6) NULL,
              `petname` VARCHAR(50) NOT NULL,
              `espece` VARCHAR(50) NOT NULL,
              `race` VARCHAR(50) NOT NULL,
              `id_gender` INT(11) NOT NULL,
              `activite` VARCHAR(60) NOT NULL,
              `age` VARCHAR(60) NOT NULL,
              `date_birth` VARCHAR(50) NULL,
              `pathologie` VARCHAR(60) NULL,
              `stade_physio` VARCHAR(60) NOT NULL,
              `poids_actuel` DECIMAL(20,2) NOT NULL,
              `poids_ideal` DECIMAL(20,2) NOT NULL,
              `be` INT(11) NULL,
              `nbr_aliment` INT(11) NOT NULL,
              `product_id_mvs1` INT(11) NOT NULL,
              `product_id_mvs2` INT(11) NULL,
              `product_id_mvs3` INT(11) NULL,
              `qte_aliment1` INT(11) NOT NULL,
              `qte_aliment2` INT(11) NULL,
              `qte_aliment3` INT(11) NULL,
              `transition12` INT(11) NULL,
              `transition23` INT(11) NULL,
              `date_add` DATETIME NOT NULL,
              `date_upd` DATETIME NOT NULL,
              `deleted` TINYINT(1) NOT NULL,
			   PRIMARY KEY (`id_recommandation`)
			);';

        return Db::getInstance()->execute($query);
    }

    public function delete()
    {
        $this->deleted = true;

        return parent::save();
    }
}
