<?php
namespace PrestaShop\Module\PolarisPrestaConnector;

use Currency;
use Exception;
use PrestaShop\Module\PolarisPrestaConnector\Models\Voucher;
use PrestaShopCollection;
use StockAvailable;

/**
 * Synchronisation des bons de réduction
 */
class SyncerVouchers
{
    /**
     * Synchroniseur
     * 
     */
    private Syncer $syncer;
    /**
     * Indicateur de progression
     */
    private SyncProgress $progress;

    /**
     * Constructeur
     * 
     * @param Syncer $syncer Synchroniseur
     * @param SyncProgress|null $progress Indicateur de progression
     */
    public function __construct(Syncer $syncer, SyncProgress|null $progress = null)
    {
        $this->syncer = $syncer;
        $this->progress = $progress ?? new SyncProgress($syncer);
    }

    /**
     * Synchronisation des stocks
     */
    public function sync()
    {
        $bridge = $this->syncer->bridge;

        $startTime = microtime(true);
        $nbRefs = 0;

        $this->progress->startStep("import_vouchers", "Importation des bons de réduction", "%d bons importés");
        try
        {
            // On récupère les bons depuis le pont, en boucle
            while ($vouchers = $bridge->pullVouchers())
                $nbRefs += $this->syncVouchers($vouchers);

            $stopTime = microtime(true);
            if ($nbRefs > 0)
                $this->syncer->audit(sprintf("[INF] Synchronisation de %d bons effectuée en %.2f secondes", $nbRefs, $stopTime - $startTime));    
        }
        catch (Exception $e)
        {
            $this->syncer->audit(sprintf("[ERR] Erreur lors de la synchronisation des bons : %s", $e->getMessage()));            
            $this->progress->error('import_vouchers', $e->getMessage());
        }
        finally
        {
            $this->progress->endStep("import_vouchers");
        }
    }

    /**
     * Synchronisation des bons précisés
     * 
     * @param array<Voucher> $vouchers Bons à synchroniser
     * @return int Nombre de bons synchronisés 
     */
    public function syncVouchers(array & $vouchers) : int
    {
        $nbDone = 0;

        $cfg = $this->syncer->module->getCfg();

        $type_import_options = [];
        foreach ($cfg->get(SyncConfiguration::CFG_VOUCHER_IMPORT_TYPES) ?? [] as $type => $actif)
            $type_import_options[$type] = $actif;

        // Faisons des paquets de 100 vouchers max.
        $nbAtATime = 100;
        while (count($vouchers) > 0)
        {
            $vouchers_slice = array_slice($vouchers, 0, $nbAtATime);
            $vouchers = array_slice($vouchers, $nbAtATime);
            
            // Le plus simple est de charger tous les cartrule de la bdd en mémoire et de les comparer
            $existingVouchers = [];

            // $voucher est un \CartRule, on fait le transtypage depuis $voucher
            /** @var \CartRule $voucher */
            foreach (
                (new PrestaShopCollection('CartRule'))->sqlWhere("code IN ('".implode("','", array_map(function($v) { return $v->code; }, $vouchers_slice)) . "')")->getAll() as $voucher)
                $existingVouchers[$voucher->code] = $voucher;

            // On a maintenant un tableau de bons existants par code
            // On parcours les bons à synchroniser
            foreach ($vouchers_slice as $voucher)
            {
                $nbDone++;
                $this->progress->progress('import_vouchers');

                if ($voucher->ignore)
                    continue;   // On ignore ce bon

                if (!isset($type_import_options[$voucher->type]) || !$type_import_options[$voucher->type])
                    continue;   // On ignore ce type de bon                

                $voucher_invalidity = null;

                // On vérifie si le voucher n'a pas un nouveau client qui n'est pas/plus sur la plateforme
                if ($voucher->customer_id < 0)
                {
                    // On ignore le bon car il est destiné à un client qui n'existe pas sur cette plateforme
                    // on le signale dans le journal d'audit
                    $voucher_invalidity = sprintf("le bon est destiné à un client inexistant sur cette plateforme", $voucher->code);
                }
                else if ($voucher->quantity <= 0)
                {
                    // On supprime le bon
                    $voucher_invalidity = sprintf("le bon a été utilisé !", $voucher->code);
                }
                else if (!$voucher->active)
                {
                    // Bon inactif !
                    $voucher_invalidity = sprintf("le bon a été désactivé sous le backoffice !", $voucher->code);
                }

                $cartRule = $existingVouchers[$voucher->code] ?? null;
                if ($cartRule === null)
                {
                    // On crée le bon, sauf s'il est invalide
                    if ($voucher_invalidity)
                    {
                        $this->syncer->audit(sprintf("[INF] Le bon %s a été ignoré : ", $voucher->code, $voucher_invalidity));
                        continue; // ce qui est visiblement le cas
                    }

                    $cartRule = new \CartRule();                    
                }
                else
                {
                    // Doit on supprimer le bon ?
                    if ($voucher_invalidity)
                    {
                        // On supprime le bon
                        $cartRule->active = 0;
                        $cartRule->save();
                        $this->syncer->audit(sprintf("[INF] Le bon %s a été désactivé car %s", $voucher->code, $voucher_invalidity));
                        continue;
                    }                    
                }

                // Autrement on update ou modifier le bon !
                $voucherAudit = new AuditHelper($cartRule);

                // On met à jour
                $cartRule->code = $voucher->code;
                $cartRule->reduction_amount = $voucher->amountTTC;
                $cartRule->reduction_percent = $voucher->reduction * 100;
                
                $cartRule->date_from = $voucher->startDate ? $voucher->startDate->format('Y-m-d').' 00:00:00' : date('Y-m-d').' 00:00:00';
                $cartRule->date_to = $voucher->expirationDate ? $voucher->expirationDate->format('Y-m-d').' 00:00:00' : '2030-01-01 00:00:00';
                $cartRule->minimum_amount = $voucher->minimumAmount;
                $cartRule->minimum_amount_tax = 1;
                // On initialise le même nom pour toutes les langues du système
                $cartRule->name = [];
                foreach (\Language::getLanguages(true) as $lang)
                    $cartRule->name[$lang['id_lang']] = $voucher->name;
                $cartRule->active = $voucher->active;
                $cartRule->quantity = $voucher->quantity;
                $cartRule->quantity_per_user = 1;
                // Pas d'utilisation partielle de ce bon                
                $cartRule->partial_use = false;
                $cartRule->free_shipping = false;
                $cartRule->reduction_tax = 1;
                // Devise par défaut
                $cartRule->reduction_currency = Currency::getDefaultCurrency()->id;

                // Si le bon a un client, le mettre en avant
                $cartRule->id_customer = $voucher->customer_id;

                $cartRule->highlight = isset($cartRule->id_customer) && $cartRule->id_customer > 0;
                
                $voucherAudit->save($this->syncer);
            }
        }

        return $nbDone;
    }
}