<?php

declare(strict_types=1);

/**
 * Created by Aurélien RICHAUD (16/01/2017 16:24)
 */
class Clinique extends ObjectModel
{
    public const TABLE = 'myvetshop_clinique';

    public const CARRIER_DOMICILE = 'domicile';
    public const CARRIER_CLINIQUE = 'clinique';
    public const CARRIER_INCONNU = 'inconnu';

    /**
     * @var array<int, float>
     */
    protected static $reductionsByCat
        = [
            // Alimentation diététique
            33 => 0.030,
            25 => 0.030,
            30 => 0.030,
            // Alimentation médicalisée
            620 => 0.030,
            621 => 0.030,
            // Alimentation physiologique
            27 => 0.100,
            32 => 0.100,
            // Alimentation premium
            615 => 0.100,
            617 => 0.100,
        ];

    /**
     * @var Employee|null
     */
    protected $cacheEmployee = null;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @var bool
     */
    public $masquer_logo;

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

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

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

    /**
     * @var string|null
     */
    public $message;

    /**
     * @var bool
     */
    public $rurale;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @var bool
     */
    public $don;

    /**
     * @var array<string, mixed>
     *
     * @see ObjectModel::$definition
     */
    public static $definition
        = [
            'table' => self::TABLE,
            'primary' => 'id_myvetshop_clinique',
            'multilang' => false,
            'multilang_shop' => false,
            'fields' => [
                // ID Externe
                'id_sso' => ['type' => self::TYPE_INT],

                // Clés étrangères
                'id_employee' => ['type' => self::TYPE_INT],
                'id_carrier' => ['type' => self::TYPE_INT],
                'id_carrier_home' => ['type' => self::TYPE_INT],
                'id_group' => ['type' => self::TYPE_INT],
                'id_group_rural' => ['type' => self::TYPE_INT],
                'id_store' => ['type' => self::TYPE_INT],

                // Informations supplémentaires
                'code_privilege' => ['type' => self::TYPE_STRING, 'required' => true, 'size' => 10],
                'centrale' => ['type' => self::TYPE_STRING, 'required' => true, 'size' => 10],
                'id_warehouse' => ['type' => self::TYPE_INT, 'required' => true],
                'code_client' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 10],
                'mdp' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 10],
                'code_filiere' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 10],

                // Thème
                'theme' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 10],
                'masquer_logo' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool', 'required' => false],

                // E-Mail pour le contact
                'email_original' => ['type' => self::TYPE_STRING, 'validate' => 'isEmail', 'required' => false],

                // Informations concernant la livraison
                'jours_livraison' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],

                // URL pour la prise de rendez-vous en ligne
                'url_rendez_vous' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 250],
                'message' => ['type' => self::TYPE_HTML, 'required' => false, 'validate' => 'isCleanHtml', 'size' => 3999999999999],
                'rurale' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool', 'required' => false],

                // Flag pour la suppression
                'deleted' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool', 'required' => false],

                // Vétérinaire 1
                'vetoAprenom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoAnom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoAurlrdv' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 100],

                // Vétérinaire 2
                'vetoBprenom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoBnom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoBurlrdv' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 100],

                // Vétérinaire 3
                'vetoCprenom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoCnom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoCurlrdv' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 100],

                // Vétérinaire 4
                'vetoDprenom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoDnom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoDurlrdv' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 100],

                // Vétérinaire 5
                'vetoEprenom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoEnom' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 55],
                'vetoEurlrdv' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 100],

                // Activation / désactivation de la possibilité de faire un don
                'don' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool', 'required' => false],
            ],
        ];

    /**
     * @return Employee
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function getEmployee(): Employee
    {
        if (is_null($this->cacheEmployee)) {
            return new Employee($this->id_employee);
        }

        return $this->cacheEmployee;
    }

    /**
     * @param bool $auto_date
     * @param bool $null_values
     *
     * @return bool
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     *
     * {@inheritDoc}
     */
    public function add($auto_date = true, $null_values = false): bool
    {
        $db = Db::getInstance();

        $duplicate = $db->getValue('SELECT c.id_myvetshop_clinique FROM `'
            . _DB_PREFIX_ . Clinique::TABLE
            . '` c WHERE c.code_privilege = "' . $db->escape($this->code_privilege) . '"'
        );

        if ($duplicate) {
            return false;
        }

        if (!$this->id_employee) {
            $lastname = Tools::getValue('lastname');

            $employee = new Employee();
            $employee->id_profile = '5';
            $employee->id_lang = '1';
            $employee->firstname = 'Clinique vétérinaire';
            $employee->lastname = $lastname ? $lastname : $this->code_privilege;
            $employee->email = $this->code_privilege . '@myvetshop.fr';
            $employee->masquer_logo = false;
            $employee->setWsPasswd($this->code_privilege . '@myvetshop.fr' . rand(99999, 999999));
            $employee->add();

            $this->id_employee = $employee->id;
        }

        if (!$this->id_group) {
            $group = new Group();
            $group->name = [Context::getContext()->language->id => $this->code_privilege];
            $group->price_display_method = 0;
            $group->add();

            $this->id_group = $group->id;
        }

        if ($this->rurale && !$this->id_group_rural) {
            $group = new Group();
            $group->name = [Context::getContext()->language->id => $this->code_privilege . '-pro'];
            // Affichage HT des prix
            $group->price_display_method = 1;
            $group->add();

            $this->id_group_rural = $group->id;
        }

        if (!$this->id_carrier && !$this->id_myvetshop_clinique) {
            $carrier = new Carrier();
            $carrier->name = 'Clinique vétérinaire ' . $this->code_privilege;
            $carrier->active = true;
            $carrier->is_free = true;
            $carrier->shipping_method = 1;
            $carrier->delay = [Context::getContext()->language->id => 'Livraison en 2 à 4 jours ouvrés (hors corse)']; /* @phpstan-ignore-line */
            $carrier->domicile = 0;
            $carrier->add();
            $carrier->setTaxRulesGroup(0);

            // Groupes de client
            $carriers = [$this->id_group];
            if ($this->id_group_rural) {
                $carriers[] = $this->id_group_rural;
            }

            $carrier->addZone(1);
            $carrier->setGroups($carriers, true);
            // Image
            copy(_PS_SHIP_IMG_DIR_ . 'img-clinique.jpg', _PS_SHIP_IMG_DIR_ . $carrier->id . '.jpg');

            $this->id_carrier = $carrier->id;
        }

        if (!$this->id_carrier_home && !$this->id_myvetshop_clinique) {
            $carrier = new Carrier();
            $carrier->name = 'Livraison à domicile';
            $carrier->active = true;
            $carrier->is_free = false;
            $carrier->shipping_method = 1;
            $carrier->max_weight = 40;
            $carrier->range_behavior = 1;
            $carrier->delay = [Context::getContext()->language->id => '4 jours']; /* @phpstan-ignore-line */
            $carrier->domicile = 1;

            $carrier->add();
            // Zone + Rule Group
            $carrier->addZone(1);
            $carrier->setTaxRulesGroup(7);

            $carriers = [$this->id_group];
            if ($this->id_group_rural) {
                $carriers[] = $this->id_group_rural;
            }

            $carrier->setGroups($carriers, true);

            // Image
            copy(_PS_SHIP_IMG_DIR_ . 'img-domicile.jpg', _PS_SHIP_IMG_DIR_ . $carrier->id . '.jpg');

            /////////////////////////////////////
            // Tarif
            $range = new RangeWeight();

            // On créé un range jusqu'à 40 Kg
            $range->id_carrier = $carrier->id;
            $range->delimiter1 = 0;
            $range->delimiter2 = 40;

            $range->add();

            // Supprime le devilery gratuit créé par défaut
            $db->execute(
                'DELETE FROM `' . _DB_PREFIX_ . 'delivery` WHERE id_range_weight = ' . (int) $range->id
            );
            // Ajoute le tarif (14 €)
            $db->execute(
                'INSERT INTO `' . _DB_PREFIX_ . 'delivery` (id_shop, id_shop_group, id_carrier, id_range_weight, id_zone, price) VALUES (1, 1,' . $carrier->id . ', ' . $range->id . ', 1, 14)'
            );

            // Enregistre l'ID du transporteur à domicile
            $this->id_carrier_home = $carrier->id;
        }

        // Supprime les associations inutiles
        Db::getInstance()->execute(
            'DELETE FROM `' . _DB_PREFIX_ . 'carrier_group` WHERE `id_group` = ' . (int) $this->id_group . ' AND id_carrier NOT IN (' . (int) $this->id_carrier . ', ' . (int) $this->id_carrier_home . ')'
        );

        if (!$this->id_store) {
            $store = new Store();
            $store->name = 'Clinique vétérinaire ' . $this->code_privilege;
            $store->address1 = 'Inconnu';
            $store->city = 'Paris';
            $store->id_country = 8;
            $store->latitude = 0;
            $store->longitude = 0;
            $store->email = $this->code_privilege . '@myvetshop.fr';
            $store->hours = '';
            $store->add();

            $this->id_store = $store->id;
        }

        return parent::add($auto_date, $null_values);
    }

    /**
     * @param bool $null_values
     *
     * @return bool
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     *
     * {@inheritDoc}
     */
    public function update($null_values = false): bool
    {
        // Création du groupe RURALE au besoin
        if ($this->rurale && !$this->id_group_rural) {
            $group = new Group();
            $group->name = [Context::getContext()->language->id => $this->code_privilege . '-pro'];
            // Affichage HT des prix
            $group->price_display_method = 1;
            $group->add();

            $this->id_group_rural = $group->id;
        }

        // Association avec la livraison en clinique
        $carrier = new Carrier($this->id_carrier);
        $carrierGroups = array_map(
            function ($row) {
                return $row['id_group'];
            },
            $carrier->getGroups()
        );
        if (!in_array($this->id_group, $carrierGroups)) {
            $carrierGroups[] = $this->id_group;
            $carrier->setGroups($carrierGroups);
        }
        if ($this->id_group_rural && !in_array($this->id_group_rural, $carrierGroups)) {
            $carrierGroups[] = $this->id_group_rural;
            $carrier->setGroups($carrierGroups);
        }

        // Association avec la livraison à domicile
        $carrier = new Carrier($this->id_carrier_home);
        $carrierGroups = array_map(
            function ($row) {
                return $row['id_group'];
            },
            $carrier->getGroups()
        );
        if (!in_array($this->id_group, $carrierGroups)) {
            $carrierGroups[] = $this->id_group;
            $carrier->setGroups($carrierGroups);
        }
        if ($this->id_group_rural && !in_array($this->id_group_rural, $carrierGroups)) {
            $carrierGroups[] = $this->id_group_rural;
            $carrier->setGroups($carrierGroups);
        }

        return parent::update($null_values);
    }

    /**
     * Récupère la liste des commandes de la clinique (par défaut : les 10 dernières)
     *
     * @return Order[]
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function getOrders(int $limit = 10, int $start = 0): array
    {
        $db = Db::getInstance(false);

        $query
            = 'SELECT o.*
                    FROM `' . _DB_PREFIX_ . 'orders` o
                    INNER JOIN `' . _DB_PREFIX_ . 'customer` c ON `o`.`id_customer` = `c`.`id_customer`
                    INNER JOIN `' . _DB_PREFIX_ . 'group_lang` g ON `c`.`id_default_group` = `g`.`id_group`
                    WHERE `g`.`name` = "' . $db->escape($this->code_privilege) . '"
                    ORDER BY `o`.`invoice_date` DESC';
        if ($limit) {
            $query .= ' LIMIT ' . ($start ? (int) $start . ', ' : '') . (int) $limit;
        }

        $result = $db->executeS($query);

        if (!is_array($result)) {
            $result = [];
        }

        return ObjectModel::hydrateCollection(Order::class, $result);
    }

    /**
     * @throws PrestaShopDatabaseException
     */
    public function getOrderCount(): string
    {
        $db = Db::getInstance(false);

        $query
            = 'SELECT COUNT(o.id_order) AS `count`
                    FROM `' . _DB_PREFIX_ . 'orders` o
                    INNER JOIN `' . _DB_PREFIX_ . 'customer` c ON `o`.`id_customer` = `c`.`id_customer`
                    INNER JOIN `' . _DB_PREFIX_ . 'group_lang` g ON `c`.`id_default_group` = `g`.`id_group`
                    WHERE `g`.`name` = "' . $db->escape($this->code_privilege) . '"';

        $ret = $db->executeS($query);

        if (is_array($ret) && isset($ret[0]['count'])) {
            return $ret[0]['count'];
        }

        return '0';
    }

    /**
     * Récupère la liste des clients de la clinique
     *
     * @return Customer[]
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function getCustomers(int $limit = 10, int $start = 0): array
    {
        $db = Db::getInstance(false);

        $query
            = 'SELECT c.*
                    FROM `' . _DB_PREFIX_ . 'customer` c
                    INNER JOIN `' . _DB_PREFIX_ . 'group_lang` g ON `c`.`id_default_group` = `g`.`id_group`
                    WHERE `c`.`deleted` = 0 AND `g`.`name` = "' . $db->escape($this->code_privilege) . '"
                    ORDER BY `c`.`date_add` DESC';
        if ($limit) {
            $query .= ' LIMIT ' . ($start ? (int) $start . ', ' : '') . (int) $limit;
        }

        $result = $db->executeS($query);

        if (!is_array($result)) {
            $result = [];
        }

        return ObjectModel::hydrateCollection(Customer::class, $result);
    }

    /**
     * @throws PrestaShopDatabaseException
     */
    public function getCustomerCount(): string
    {
        $db = Db::getInstance(false);

        $query
            = 'SELECT COUNT(c.id_customer) AS `count`
                    FROM `' . _DB_PREFIX_ . 'customer` c
                    INNER JOIN `' . _DB_PREFIX_ . 'group_lang` g ON `c`.`id_default_group` = `g`.`id_group`
                    WHERE `g`.`name` = "' . $db->escape($this->code_privilege) . '"';

        $ret = $db->executeS($query);

        if (is_array($ret) && isset($ret[0]['count'])) {
            return $ret[0]['count'];
        }

        return '0';
    }

    /**
     * @return int[]|null
     *
     * @throws PrestaShopDatabaseException
     */
    public function getAccessoireCategories(): ?array
    {
        $db = Db::getInstance();
        $centraleCatName = '';

        switch ($this->centrale) {
            case 'alcyon':
                $centraleCatName = 'Alcyon';
                break;

            case 'centravet':
                $centraleCatName = 'CentraVet';
                break;

            case 'coveto':
                $centraleCatName = 'CoVeto';
                break;

            case 'hippocampe':
                $centraleCatName = 'Hippocampe';
                break;

            default:
                return null;
        }

        $idCatCentrale = $db->getValue('SELECT `id_category` FROM `ps_category_lang` WHERE `name` = "' . $db->escape($centraleCatName) . '"');

        if (!$idCatCentrale) {
            return null;
        }

        $idCatAccessoires = $db->getValue(
            'SELECT `c`.`id_category`'
            . ' FROM `ps_category` c'
            . ' INNER JOIN `ps_category_lang` cl ON `cl`.`id_category` = `c`.`id_category`'
            . ' WHERE `c`.`id_parent` = ' . (int) $idCatCentrale . ' AND `cl`.`name` = "' . $db->escape('Accessoires') . '"'
        );
        if (!$idCatAccessoires) {
            return null;
        }

        $ret = [(int) $idCatAccessoires];

        $result = $db->executeS('SELECT c.* FROM `ps_category` c WHERE id_parent = ' . (int) $idCatAccessoires);

        if (!is_array($result)) {
            $result = [];
        }

        foreach ($result as $row) {
            $ret[] = (int) $row['id_category'];
        }

        return $ret;
    }

    /**
     * @throws PrestaShopDatabaseException
     */
    public static function getCliniqueByEmployee(int $id_employee): ?int
    {
        $db = Db::getInstance(false);

        $cliniques = $db->executeS(
            '
                    SELECT c.*
                    FROM `' . _DB_PREFIX_ . self::TABLE . '` c
                    WHERE `c`.`id_employee` = ' . (int) $id_employee
        );

        if (!is_array($cliniques)) {
            $cliniques = [];
        }

        if (0 == count($cliniques)) {
            return null;
        }

        return (int) $cliniques[0]['id_myvetshop_clinique'];
    }

    /**
     * @throws PrestaShopDatabaseException
     */
    public static function getCliniqueByCarrier($id_carrier): ?int
    {
        $db = Db::getInstance(false);

        $cliniques = $db->executeS(
            '
                    SELECT c.*
                    FROM `' . _DB_PREFIX_ . self::TABLE . '` c
                    WHERE `c`.`id_carrier` = ' . (int) $id_carrier . ' OR `c`.`id_carrier_home` = ' . (int) $id_carrier
        );

        if (!is_array($cliniques)) {
            $cliniques = [];
        }

        if (0 == count($cliniques)) {
            return null;
        }

        return (int) $cliniques[0]['id_myvetshop_clinique'];
    }

    /**
     * @throws PrestaShopDatabaseException
     */
    public static function getCliniqueByGroup($id_group): ?int
    {
        $db = Db::getInstance(false);

        $cliniques = $db->executeS(
            'SELECT c.*
                    FROM `' . _DB_PREFIX_ . self::TABLE . '` c
                    WHERE `c`.`id_group` = ' . (int) $id_group . ' OR `c`.`id_group_rural` = ' . (int) $id_group
        );

        if (!is_array($cliniques)) {
            $cliniques = [];
        }

        if (0 == count($cliniques)) {
            return null;
        }

        return (int) $cliniques[0]['id_myvetshop_clinique'];
    }

    /**
     * @throws PrestaShopDatabaseException
     */
    public static function getCliniqueByIdSSO(int $id_sso): ?int
    {
        $db = Db::getInstance(false);

        $cliniques = $db->executeS(
            'SELECT c.*
                    FROM `' . _DB_PREFIX_ . self::TABLE . '` c
                    WHERE `c`.`id_sso` = ' . (int) $id_sso
        );

        if (!is_array($cliniques)) {
            $cliniques = [];
        }

        if (0 == count($cliniques)) {
            return null;
        }

        return (int) $cliniques[0]['id_myvetshop_clinique'];
    }

    /**
     * @throws PrestaShopDatabaseException
     */
    public static function getByCodePrivilege(string $code_privilege): ?int
    {
        $db = Db::getInstance(false);

        $cliniques = $db->executeS(
            'SELECT c.*
                    FROM `' . _DB_PREFIX_ . self::TABLE . '` c
                    WHERE `c`.`code_privilege` = "' . $db->escape($code_privilege) . '"'
        );

        if (!is_array($cliniques)) {
            $cliniques = [];
        }

        if (0 == count($cliniques)) {
            return null;
        }

        return (int) $cliniques[0]['id_myvetshop_clinique'];
    }

    /**
     * Détermine si un livreur est "à domicile" ou "en clinique"
     *
     * @return string domicile, clinique ou inconnu
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public static function getCarrierType(int $id_carrier): string
    {
        $clinique_id = self::getCliniqueByCarrier($id_carrier);

        if (!$clinique_id) {
            return self::CARRIER_INCONNU;
        }

        $clinique = new Clinique($clinique_id);

        if ($id_carrier == $clinique->id_carrier) {
            return self::CARRIER_CLINIQUE;
        } elseif ($id_carrier == $clinique->id_carrier_home) {
            return self::CARRIER_DOMICILE;
        }

        return self::CARRIER_INCONNU;
    }

    /**
     * @return array<int, float>
     */
    public static function getReductionsByCat(): array
    {
        return self::$reductionsByCat;
    }
}
