<?php
namespace PrestaShop\Module\PolarisPrestaConnector;

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

/**
 * Synchronisation des cartes prépayées
 */
class SyncerPrepaidCards
{
    /**
     * 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_prepaid_cards", "Importation des cartes prépayées", "%d cartes importées");
        try
        {
            // On récupère les bons depuis le pont, en boucle
            while ($cards = $bridge->pullPrepaidCards())
                $nbRefs += $this->syncCards($cards);

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

    /**
     * Synchronisation des cartes précisés
     * 
     * @param array<PrepaidCard> $cards Cartes à synchroniser
     * @return int Nombre de bons synchronisés 
     */
    public function syncCards(array & $cards) : int
    {
        $nbDone = 0;

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

        // Faisons des paquets de 100 cartes max.
        $nbAtATime = 100;
        while (count($cards) > 0)
        {
            $cards_slice = array_slice($cards, 0, $nbAtATime);
            $cards = array_slice($cards, $nbAtATime);
            
            // Le plus simple est de charger tous les cartes 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; }, $cards_slice)) . "')")->getAll() as $voucher)
                $existingVouchers[$voucher->code] = $voucher;

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

                $card_invalidity = null;

                if (!$card->active)
                {
                    // Bon inactif !
                    $card_invalidity = sprintf("la carte n'est plus valide !", $card->code);
                }

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

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

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

                // On met à jour
                $cartRule->code = $card->code;
                $cartRule->reduction_amount = $card->amount;
               
                if ($cartRule->date_from === null)
                    $cartRule->date_from = date('Y-m-d').' 00:00:00';

                $cartRule->date_to = $card->expirationDate ? $card->expirationDate->format('Y-m-d').' 00:00:00' : '2030-01-01 00:00:00';

                // 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']] = 'Carte prépayée '.$card->name;

                $cartRule->active = $card->active;
                $cartRule->quantity = 1;
                $cartRule->quantity_per_user = 999999;

                // 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;
                $cartRule->highlight = false;
                
                $voucherAudit->save($this->syncer);
            }
        }

        return $nbDone;
    }
}