<?php

namespace PrestaShop\Module\PolarisPrestaConnector\Controller;

use PrestaShop\Module\PolarisPrestaConnector\SyncConfiguration;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use PrestaShop\Module\PolarisPrestaConnector\Syncer;
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;

class ConfigurationAjaxAdminController extends AdminController
{
    /**
     * Méthode qui est appelée depuis un code Web2 pour vérifier :
     * - (param `address`) : soit que l'URL pointe bien vers le backoffice
     * - (param `address`, `fingerprint`) : soit que si le certificat est autosigné sur une URL correcte, il est correct
     * - (param `address`, `fingerprint`, `username`, `password`) : soit que les informations de login sont corrects sur un certificat accepté, sur une URL correcte
     * 
     * La méthode autodétecte ce qu'il y a à faire selon les paramètres fourni et renvoi :
     * - { } : tout vas bien
     * - { "fingerprint" : "" } tout vas bien mais le certificat est autosigné et il faut vérifier le fingerprint
     * - { "error" : "" } : il s'agit du message d'erreur
     */
    public function connectToApiAjaxAction(Request $request)
    {
        // On récupère le bridge
        $bridge = $this->module->getBridge();

        // On délègue le traitement à la méthode du bridge
        $errorMsg = $bridge->bind([
                        "address" => $request->get('address'),
                        "fingerprint" => $request->get('fingerprint'),
                        "username" => $request->get('username'),
                        "password" => $request->get('password'),
                        "pincode" => $request->get('pincode'),
                        ]);                    

        if ($errorMsg)
        {
            // Si le message commence par un chiffre, alors c'est un code d'erreur, on l'isole
            $code = (int) preg_replace('/^(\d+).*/', '$1', $errorMsg) ?? 0;
            preg_match('/Empreinte : ([a-f0-9]{40,})/', $errorMsg, $matches);
            $fingerprint = $matches[1] ?? null;
            // Et on retire le code du message original
            $errorMsg = preg_replace('/^\d+ : /', '', $errorMsg) ?? $errorMsg;
            // Et s'il y a l'empreinte on la retire du message original
            $errorMsg = preg_replace('/Empreinte : [a-f0-9]{40,}/', '', $errorMsg) ?? $errorMsg;
            // Le message d'erreur doit commencer par une majuscule
            $errorMsg = ucfirst($errorMsg);
            return new JsonResponse(['success' => false, 'code' => $code, 'message' => $errorMsg , 'fingerprint' => $fingerprint]);
        }
        else
            return new JsonResponse(['success' => true, 'message' => '']);
    }   
    
    /**
     * Synchronisation d'un produit
     */
    public function syncProductAjaxAction(Request $request)
    {
        try
        {
            // Fin de la session pour éviter de bloquer le processus et les autres demande du même utilisateur
            if (session_id()) 
                session_write_close();
            
            // On va intercepter toutes les sorties
            ob_start();

            // On instancie un syncer
            $syncer = new Syncer($this->module, true);

            // On délègue le traitement à la méthode du syncer            
            $syncer->syncProduct($request->get('id_product'));

            // On encapule le résultat dans la sortie
            $output = ob_get_clean();

            // Si tout est bon on renvoi un message de succès
            return new JsonResponse(['success' => (strpos($output, 'ERR') === false), 'message' => $output]);
        }
        catch (\Exception $e)
        {            
            return new JsonResponse(['success' => false, 'message' => $e->getMessage()]);
        }
    }

    /**
     * Exportation d'une commande
     */
    public function exportOrderAjaxAction(Request $request)
    {
        // Fin de la session pour éviter de bloquer le processus et les autres demandes du même utilisateur
        if (session_id())
            session_write_close();

        $reference = (string) $request->get('order_reference');

        // On délègue l'export au syncer. On capture le résultat/l'erreur, mais on renverra
        // TOUJOURS ensuite le panneau rafraîchi : en cas d'erreur, le journal contient justement
        // une nouvelle entrée que l'on veut afficher immédiatement côté fiche commande.
        $success = true;
        $message = '';
        try
        {
            $syncer = new Syncer($this->module);
            $exported = $syncer->exportOrder($reference);
            $message = $exported
                ? 'La commande a été ré-exportée.'
                : 'Aucune ré-exportation nécessaire : la commande est déjà à jour (ou sans élément exportable).';
        }
        catch (\Exception $e)
        {
            $success = false;
            $message = $e->getMessage();
        }

        // Panneau d'export rafraîchi (statut + journal à jour) pour une mise à jour in-place,
        // sans recharger la page — y compris quand l'export vient d'échouer. On renvoie aussi la
        // couleur / le libellé du statut courant pour rafraîchir la pastille du lien d'onglet.
        $html = '';
        $statusColor = '';
        $statusLabel = '';
        try
        {
            $view = $this->module->getOrderExportView($reference);
            $statusColor = $view['status_color'];
            $statusLabel = $view['status_label'];

            $renderer = SymfonyContainer::getInstance()->get($this->module->name . '.twig_renderer');
            $html = $renderer->render(
                $this->module->TplPath . 'hook/order_export_panel.html.twig',
                $view
            );
        }
        catch (\Throwable $e)
        {
            $html = '';
        }

        return new JsonResponse([
            'success'     => $success,
            'message'     => $message,
            'html'        => $html,
            'statusColor' => $statusColor,
            'statusLabel' => $statusLabel,
        ]);
    }

    /**
     * Verrouillage d'un produit
     */
    public function lockProductAjaxAction(Request $request)
    {
        try
        {
            $action = $request->get('action');
            $id_product = $request->get('id_product');

            if ($action == "lock")
                $this->module->getCfg()->lockProduct($id_product);
            else
                $this->module->getCfg()->unlockProduct($id_product);

            // Si tout est bon on renvoi un message de succès
            return new JsonResponse(['success' => true, 'message' => '']);
        }
        catch (\Exception $e)
        {
            return new JsonResponse(['success' => false, 'message' => $e->getMessage()]);
        }
    }

    /**
     * Programme une resynchronisation totale
     */
    public function syncResyncAction(Request $request)
    {
        try
        {
            // On instancie un syncer
            $syncer = new Syncer($this->module);
            $cfg = $this->module->getCfg();

            // Demande de resynchronisation totale pour la prochaine fois
            $syncer->bridge->resetSyncPosition();

            // On marque toutes les synchronisations comme jamais effectuées (Fix #142)
            $cfg->set(SyncConfiguration::CFG_SYNCS_LAST, []);

            // On appelle une URL mais on attend pas la réponse (cela permet de lancer le processus en tâche de fond)
            // URL à appeler : le contrôleur front cron
            // avec curl ?
            $url = \Context::getContext()->link->getModuleLink($this->module->name, 'cron', ['guard' => $cfg->get(SyncConfiguration::CFG_GUARD_TOKEN) ], true);

            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
            curl_setopt($ch, CURLOPT_TIMEOUT_MS, 5000); // on coupe vite
            curl_setopt($ch, CURLOPT_NOBODY, true);  // on ne lit pas le corps
            curl_exec($ch);
            curl_close($ch);


            // Si tout est bon on renvoi un message de succès
            return new JsonResponse(['success' => true, 'message' => '']);
        }
        catch (\Exception $e)
        {
            return new JsonResponse(['success' => false, 'message' => $e->getMessage()]);
        }
    }

    /**
     * Obtient la progression de la synchronisation en cours ou null si aucune synchronisation en cours
     */
    public function getSyncProgressAjaxAction()
    {
        try
        {
            // On récupère la progression sans instancier (on gagne du temps)
            $progress = Syncer::getSyncProgress($this->module);

            // Si tout est bon on renvoi un message de succès
            return new JsonResponse(['success' => true, 'progress' => $progress->toArray()]);
        }
        catch (\Exception $e)
        {
            return new JsonResponse(['success' => false, 'message' => $e->getMessage()]);
        }
    }

    
    /**
     * Tirage de l'environnement
     *
     * Paramètre `clean` (défaut 1) : nettoie les mappages vides avant le tirage (bouton manuel).
     * Le déclenchement automatique en arrière-plan après une association utilise `clean=0` afin
     * de préserver d'éventuels mappages déjà saisis.
     */
    public function pullenvAjaxAction(Request $request)
    {
        try
        {
            // Tirage de l'environnement
            $this->module->getBridge()->pullEnvironment(((int) $request->get('clean', 1)) === 1);

            // Si tout est bon on renvoi un message de succès
            return new JsonResponse(['success' => true]);
        }
        catch (\Exception $e)
        {
            return new JsonResponse(['success' => false, 'message' => $e->getMessage()]);
        }
    }

}