<?php
namespace PrestaShop\Module\LCVPrestaConnector;

use LCVPrestaConnector;

class Upgrade_9_0_30 {
    /**
     * Refonte du suivi d'exportation des commandes (ticket #248).
     *
     * Historiquement, l'état « exporté / erreur d'export » d'une commande était matérialisé
     * par deux OrderState PrestaShop posés sur la commande, ce qui écrasait son état métier
     * réel (Expédiée, Livrée, Remboursée…) dans `current_state` et l'historique.
     *
     * Cette migration :
     *   1. crée la table journal `{prefix}orders_export_log` (append-only, datée) ;
     *   2. reconstruit ce journal à partir des passages historiques dans les deux états module ;
     *   3. repositionne `orders.current_state` sur le dernier état métier réel ;
     *   4. purge les lignes d'historique liées aux deux états module ;
     *   5. désactive les deux OrderState (deleted = 1) pour qu'ils disparaissent des listes.
     *
     * Les étapes 2 à 5 ne s'exécutent qu'une seule fois (garde « journal vide ») et uniquement
     * si les deux états ont réellement existé sur cette installation. Sur une installation neuve,
     * seule la table est créée.
     */
    public function upgrade(LCVPrestaConnector $module, $db)
    {
        // Le bouton « Réexporter » a été déplacé de la barre d'actions vers l'onglet « Export »
        // de la fiche commande : on désenregistre le hook du bandeau d'actions, devenu inutile.
        $module->unregisterHook('actionGetAdminOrderButtons');

        $tableName = $module->TblPrefix . 'orders_export_log';

        // ────────────────────────────────────────────────────────────────────
        // Étape 1 : création de la table journal (si absente) + clé étrangère
        // ────────────────────────────────────────────────────────────────────
        $tableExists = (int) $db->getValue('
            SELECT COUNT(*) FROM information_schema.TABLES
            WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = \'' . pSQL($tableName) . '\'');

        if (!$tableExists) {
            if (!$db->execute('
                CREATE TABLE IF NOT EXISTS `' . $tableName . '` (
                    `id_export_log` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
                    `id_order`      INT(10) UNSIGNED NOT NULL,
                    `revision`      INT(10) UNSIGNED DEFAULT NULL,
                    `status`        VARCHAR(20) NOT NULL,
                    `message`       TEXT NULL,
                    `date_add`      DATETIME NOT NULL,
                    PRIMARY KEY (`id_export_log`),
                    KEY `idx_order` (`id_order`)
                ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8mb4;'))
                throw new \Exception('Erreur lors de la création de la table du journal d\'exportation : ' . $db->getMsgError());

            // On lie le champ `id_order` à la table des commandes (comme orders_updates)
            if (!$db->execute('
                ALTER TABLE `' . $tableName . '`
                ADD FOREIGN KEY (`id_order`) REFERENCES `' . _DB_PREFIX_ . 'orders`(`id_order`)
                ON UPDATE CASCADE ON DELETE CASCADE;'))
                throw new \Exception('Erreur lors de la création de la clé étrangère du journal d\'exportation : ' . $db->getMsgError());
        }

        // ────────────────────────────────────────────────────────────────────
        // Récupération des identifiants des deux états module (s'ils existent)
        // ────────────────────────────────────────────────────────────────────
        $cfg = $module->getCfg();
        $exp = (int) $cfg->get(SyncConfiguration::CFG_ORDER_EXPORT_STATE);
        $err = (int) $cfg->get(SyncConfiguration::CFG_ORDER_ERROR_EXPORT_STATE);
        $ids = array_values(array_filter([$exp, $err]));

        // Rien à reconstruire/nettoyer : installation neuve (états jamais créés)
        if (!$ids)
            return;

        $idList = implode(', ', $ids);

        // Garde d'idempotence : on ne reconstruit/nettoie qu'une seule fois
        $alreadyBuilt = (int) $db->getValue('SELECT COUNT(*) FROM `' . $tableName . '`');
        if ($alreadyBuilt > 0)
            return;

        // ────────────────────────────────────────────────────────────────────
        // Étape 2 : reconstruction du journal depuis l'historique des commandes
        //   (date = order_history.date_add ; cause indisponible dans l'ancien système)
        //   Insertion en ordre chronologique par commande ⇒ id_export_log croissant
        //   = ordre chronologique ⇒ « dernière entrée » = MAX(id_export_log).
        // ────────────────────────────────────────────────────────────────────
        if ($exp && $err)
            $statusExpr = 'CASE WHEN oh.id_order_state = ' . $exp . ' THEN \'exported\' ELSE \'error\' END';
        elseif ($exp)
            $statusExpr = '\'exported\'';
        else
            $statusExpr = '\'error\'';

        if (!$db->execute('
            INSERT INTO `' . $tableName . '` (`id_order`, `revision`, `status`, `message`, `date_add`)
            SELECT oh.id_order, NULL, ' . $statusExpr . ', NULL, oh.date_add
            FROM `' . _DB_PREFIX_ . 'order_history` oh
            WHERE oh.id_order_state IN (' . $idList . ')
            ORDER BY oh.id_order ASC, oh.date_add ASC, oh.id_order_history ASC;'))
            throw new \Exception('Erreur lors de la reconstruction du journal d\'exportation : ' . $db->getMsgError());

        // ────────────────────────────────────────────────────────────────────
        // Étape 3 : repositionnement de orders.current_state sur le dernier état
        //   MÉTIER réel (état ∉ états module). SQL direct volontaire : on répare la
        //   valeur dénormalisée `current_state`, sans repasser par l'API OrderHistory
        //   (qui rajouterait une ligne d'historique + hooks/e-mails/mouvements de stock).
        //   Garde EXISTS(...) : on ne touche jamais une commande qui n'aurait aucun
        //   autre état d'historique (on ne veut pas de current_state NULL).
        // ────────────────────────────────────────────────────────────────────
        if (!$db->execute('
            UPDATE `' . _DB_PREFIX_ . 'orders` o
            SET o.current_state = (
                SELECT oh.id_order_state FROM `' . _DB_PREFIX_ . 'order_history` oh
                WHERE oh.id_order = o.id_order AND oh.id_order_state NOT IN (' . $idList . ')
                ORDER BY oh.date_add DESC, oh.id_order_history DESC LIMIT 1)
            WHERE o.current_state IN (' . $idList . ')
              AND EXISTS (
                SELECT 1 FROM `' . _DB_PREFIX_ . 'order_history` oh2
                WHERE oh2.id_order = o.id_order AND oh2.id_order_state NOT IN (' . $idList . '));'))
            throw new \Exception('Erreur lors du repositionnement de l\'état des commandes : ' . $db->getMsgError());

        // ────────────────────────────────────────────────────────────────────
        // Étape 4 : purge des lignes d'historique liées aux deux états module.
        //   IMPÉRATIF : après les étapes 2 (lecture) et 3 (lecture des états non-module).
        // ────────────────────────────────────────────────────────────────────
        if (!$db->execute('
            DELETE FROM `' . _DB_PREFIX_ . 'order_history` WHERE id_order_state IN (' . $idList . ');'))
            throw new \Exception('Erreur lors de la purge de l\'historique des états d\'export : ' . $db->getMsgError());

        // ────────────────────────────────────────────────────────────────────
        // Étape 5 : désactivation des deux OrderState (deleted = 1). On conserve la
        //   ligne (pas de DELETE) pour rester résolvable et sûr vis-à-vis des FK.
        // ────────────────────────────────────────────────────────────────────
        if (!$db->execute('
            UPDATE `' . _DB_PREFIX_ . 'order_state` SET deleted = 1 WHERE id_order_state IN (' . $idList . ');'))
            throw new \Exception('Erreur lors de la désactivation des états d\'export : ' . $db->getMsgError());
    }
}
