<?php
/**
 * NOTICE OF LICENSE.
 *
 * Copyright 2022 Kosmonaft.dev
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 *  @author    Alexandre DEBUSSCHÈRE <alexandre@kosmonaft.dev>
 *  @copyright 2022 - 2023 Kosmonaft.dev
 *  @license   MIT
 */

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

/**
 * Class MRMaxCarrier
 */
class MRMaxCarrier extends Carrier
{

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

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

    /** @var MRMax */
    protected $module;

    /**
     * @param int|null $id
     * @param int|null $id_lang
     * @param MRMax $module
     */
    public function __construct($id = null, $id_lang = null, $module = null)
    {
        parent::__construct($id, $id_lang);

        if ($module != null && !$module instanceof MRMax) {
            throw new InvalidArgumentException('Module is not an instance of ColissmoMax.');
        }

        $this->module = $module ?: new MRMax();

        if ($this->id_reference) {
            $this->mode = Db::getInstance()->getValue(
                'SELECT `delivery_mode`
                FROM `'._DB_PREFIX_.'mrmax_carrier`
                WHERE `id_reference` = '.(int)$this->id_reference
            );

            $this->insurance = Db::getInstance()->getValue(
                'SELECT `insurance`
                FROM `'._DB_PREFIX_.'mrmax_carrier`
                WHERE `id_reference` = '.(int)$this->id_reference
            );
        }
    }

    /**
     * @return array
     */
    public function getDeliveryModes()
    {
        return [
            '24R' => sprintf($this->l('Delivery in %s relay'), $this->l('standard')),
            '24L' => sprintf($this->l('Delivery in %s relay'), 'XL'),
            '24X' => sprintf($this->l('Delivery in %s relay'), 'XXL'),
            'DRI' => $this->l('Colis Drive delivery'),
            'LD1' => sprintf($this->l('Home delivery %dKg with appointment %d person'), 70, 1),
            'LDS' => sprintf($this->l('Home delivery %dKg with appointment %d person'), 130, 2),
            'HOM' => $this->l('Home delivery without appointment'),
            'HOC' => $this->l('Home delivery (specific to Spain)'),
            'HOD' => $this->l('Home delivery (specific to Spain)')
        ];
    }

    public function canDeliverInCountry($iso_country)
    {
        $delivery_mode_by_country = [
            'FR' => ['24R', '24L', '24X'],
            'BE' => ['24R', '24L', '24X', 'DRI', 'LD1', 'LDS', 'HOM'],
            'LU' => ['24R', '24L', '24X', 'DRI', 'LD1', 'LDS', 'HOM'],
            'ES' => ['24R', '24L', '24X', 'DRI', 'LD1', 'LDS', 'HOM', 'HOC', 'HOD'],
            'DE' => ['DRI', 'LD1', 'LDS', 'HOM'],
            'IT' => ['DRI', 'LD1', 'LDS', 'HOM'],
            'AT' => ['DRI', 'LD1', 'LDS', 'HOM'],
            'PT' => ['DRI', 'LD1', 'LDS', 'HOM'],
            'NL' => ['DRI', 'LD1', 'LDS', 'HOM'],
        ];

        return in_array(
            Tools::strtoupper($this->mode),
            $delivery_mode_by_country[Tools::strtoupper($iso_country)]
        );
    }

    /**
     * @return array
     */
    public function getInsurances()
    {
        return [
            'NA' => $this->l('No insurance'),
            'N1' => sprintf($this->l('Complementary insurance %s'), 'N1'),
            'N2' => sprintf($this->l('Complementary insurance %s'), 'N2'),
            'N3' => sprintf($this->l('Complementary insurance %s'), 'N3'),
            'N4' => sprintf($this->l('Complementary insurance %s'), 'N4'),
            'N5' => sprintf($this->l('Complementary insurance %s'), 'N5')
        ];
    }

    /**
     * @return array
     */
    public function getCountries()
    {
        return ['FR', 'BE', 'LU', 'ES', 'DE', 'AT', 'IT', 'PT', 'NL'];
    }

    /**
     * @param string $string
     * @return string
     */
    protected function l($string)
    {
        return $this->module->l($string, self::class);
    }

    /**
     * @param string $name
     * @param string $delay
     * @param string $mode
     * @param string $insurance
     * @return bool
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function addMondialRelayCarriers($name, $delay, $mode, $insurance)
    {
        $success = true;

        // Carrier
        $carrier = new Carrier();
        $carrier->name = $name;
        $carrier->is_module = true;
        $carrier->external_module_name = $this->module->name;
        $carrier->active = 0;
        $carrier->deleted = 0;
        $carrier->need_range = true;
        $carrier->shipping_external = true;
        $carrier->range_behavior = 0;
        $carrier->shipping_method = Carrier::SHIPPING_METHOD_WEIGHT;
        $carrier->shipping_handling = false;
        $carrier->url = 'https://www.mondialrelay.fr/suivi-de-colis?numeroExpedition=@';

        foreach (Language::getLanguages() as $lang) {
            $carrier->delay[$lang['id_lang']] = $delay;
        }

        $success &= $carrier->add();

        // Image
        $success &= (bool)Tools::copy(
            dirname(__FILE__).'/../views/img/carrier_image.png',
            _PS_SHIP_IMG_DIR_.'/'.(int)$carrier->id.'.jpg'
        );

        // Group
        $groups_ids = [];
        foreach (Group::getGroups(Context::getContext()->language->id) as $group) {
            $groups_ids[] = $group['id_group'];
        }
        $carrier->setGroups($groups_ids);

        // Zones
        foreach (Zone::getZones() as $zone) {
            $carrier->addZone($zone['id_zone']);
        }

        // Ranges
        $range_price = new RangePrice();
        $range_price->id_carrier = $carrier->id;
        $range_price->delimiter1 = '0';
        $range_price->delimiter2 = '10000';
        $range_price->add();

        $range_weight = new RangeWeight();
        $range_weight->id_carrier = $carrier->id;
        $range_weight->delimiter1 = '0';
        $range_weight->delimiter2 = '10000';
        $range_weight->add();

        // Save in Db
        $success &= Db::getInstance()->insert(
            'mrmax_carrier',
            [
                'id_reference' => $carrier->id,
                'delivery_mode' => $mode,
                'insurance' => $insurance
            ]
        );

        return $success;
    }

    public function getMondialRelayCarriers($active = false)
    {
        return Db::getInstance()->executeS(
            'SELECT *
            FROM `'._DB_PREFIX_.'carrier` c
            LEFT JOIN `'._DB_PREFIX_.'mrmax_carrier` mc ON c.`id_reference` = mc.`id_reference`
            WHERE c.`id_reference` = mc.`id_reference`
            AND c.`deleted` = 0
            '.($active ? 'AND c.`active` = 1' : '')
        );
    }

    /**
     * @return bool
     */
    public function removeMondialRelayCarriers()
    {
        $success = true;

        $carrier_ids = $this->getMondialRelayCarriers();
        foreach ($carrier_ids as $carrier_id) {
            $carrier = new MRMaxCarrier($carrier_id);
            if (Validate::isLoadedObject($carrier) && !$carrier->deleted) {
                $success &= $carrier->delete();
            }
        }

        return $success;
    }

    /**
     * @return array
     * @throws PrestaShopException
     */
    public static function getMondialRelayCarrierReferences()
    {
        $carriers = Db::getInstance()->executeS(
            'SELECT DISTINCT mc.`id_reference`
            FROM `'._DB_PREFIX_.'mrmax_carrier` mc
            LEFT JOIN `'._DB_PREFIX_.'carrier` c ON c.`id_reference` = mc.`id_reference`
            WHERE c.`deleted` = 0'
        );
        $carriers = array_column($carriers, 'id_reference');

        return array_map('intval', $carriers);
    }

    /**
     * @return array
     * @throws PrestaShopException
     */
    public static function getMondialRelayCarrierIds()
    {
        $carrier_ids = [];

        foreach (self::getMondialRelayCarrierReferences() as $id_reference) {
            $tmp_carrier = Carrier::getCarrierByReference($id_reference);
            if (Validate::isLoadedObject($tmp_carrier) && $tmp_carrier->active && !$tmp_carrier->deleted) {
                $carrier_ids[] = $tmp_carrier->id;
            }
        }

        return $carrier_ids;
    }

    /**
     * @return array
     * @throws PrestaShopException
     */
    public static function getMondialRelayCarrierModes()
    {
        $carrier_modes = [];

        foreach (self::getMondialRelayCarrierReferences() as $id_reference) {
            $tmp_carrier = Carrier::getCarrierByReference($id_reference);
            if (Validate::isLoadedObject($tmp_carrier) && $tmp_carrier->active && !$tmp_carrier->deleted) {
                $carrier_modes[$tmp_carrier->id] = Db::getInstance()->getValue(
                    'SELECT `delivery_mode`
                    FROM `'._DB_PREFIX_.'mrmax_carrier`
                    WHERE `id_reference` = '.(int)$tmp_carrier->id_reference
                );
            }
        }

        return $carrier_modes;
    }

    /**
     * @param int $id_carrier
     * @return string|null
     */
    public static function getNameById($id_carrier)
    {
        $carrier = new Carrier($id_carrier);
        if (!Validate::isLoadedObject($carrier)) {
            return null;
        }

        return $carrier->name;
    }

    /**
     * @return string[]
     * @throws PrestaShopException
     */
    public static function getMRCarrierNames()
    {
        $names = [];

        foreach (self::getMondialRelayCarrierReferences() as $mode => $id_reference) {
            $tmp_carrier = Carrier::getCarrierByReference(
                $id_reference,
                Context::getContext()->language->id
            );
            if (Validate::isLoadedObject($tmp_carrier)) {
                $names[$mode] = $tmp_carrier->name;
            }
        }

        return $names;
    }
}
