<?php
namespace PrestaShop\Module\PolarisPrestaTheme\Classes;
use PrestaShopLogger;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use PrestaShop\Module\PolarisPrestaTheme\Config\ConfigTheme;
use \Imagick;


/**
 * Ensemble d'utilitaires pour la gestion des fichiers et répertoires liés au thème PrestaShop.
 */
class ThemeTools
{
    /** 
     * removeDirectory 
     *
     * Supprime le dossier $path et tout son contenu.
     * 
     * @param string $path Dossier à supprimer
     * @throws Exception en cas d'erreur lors de la suppression
     */
    public static function removeDirectory(string $path): void
    {
        if (!is_dir($path)) {
            PrestaShopLogger::addLog("ℹ️ Le répertoire n'existe pas : $path", 1);
            return;
        }
    
        $handle = opendir($path);
        if (!$handle) {
            throw new \Exception("Impossible d’ouvrir le répertoire : $path");
        }
    
        try {
            while (($entry = readdir($handle)) !== false) {
                if ($entry === '.' || $entry === '..') {
                    continue;
                }
    
                $file = $path . DIRECTORY_SEPARATOR . $entry;
    
                if (is_dir($file)) {
                    self::removeDirectory($file);
                } else {
                    if (!unlink($file)) {
                        throw new \Exception("Impossible de supprimer le fichier : $file");
                    }
                }
            }
        } finally {
            closedir($handle);
    
            if (file_exists($path) && !rmdir($path)) {
                throw new \Exception("Impossible de supprimer le répertoire : $path");
            }
        }
    }

    /** 
     * copyTheme
     *
     * copie le dossier $source et tout son contenu vers sa $destination
     * 
     * @param string $soure fichier a copier
     * @param string $destination route ou copier le fichier
     * @throws Exception en cas d'erreur lors de la copie
     */
    public static function copyTheme($source, $destination)
    {
        if (!is_dir($source)) {
            PrestaShopLogger::addLog("❌ Le dossier source n'existe pas : $source", 3);
            return false;
        }

        // Environnement de dev : le thème est monté en symlink vers assets/ du module.
        // Source et destination pointent alors sur les mêmes fichiers → on ne copie
        // rien (copy() tronquerait chaque fichier sur lui-même). No-op en production
        // où les deux répertoires sont distincts.
        if (($rs = realpath($source)) && ($rd = realpath($destination)) && $rs === $rd) {
            return true;
        }

        if (!file_exists($destination)) {
            @mkdir($destination, 0755, true);
        }
    
        $dir = opendir($source);
        if (!$dir) {
            PrestaShopLogger::addLog("❌ Impossible d'ouvrir le dossier source : $source", 3);
            return false;
        }
    
        while (($file = readdir($dir)) !== false) {
            if ($file === '.' || $file === '..') {
                continue;
            }
    
            $srcPath = $source . '/' . $file;
            $destPath = $destination . '/' . $file;
    
            if (is_dir($srcPath)) {
                if (!self::copyTheme($srcPath, $destPath)) {
                    closedir($dir);
                    return false;
                }
            } else {
                if (!copy($srcPath, $destPath)) {
                    PrestaShopLogger::addLog("❌ Erreur lors de la copie de $srcPath vers $destPath", 3);
                    closedir($dir);
                    return false;
                }
            }
        }
    
        closedir($dir);
        return true;
    }

     
    /**
     * uploadImage
     *
     * Upload une image Symfony (UploadedFile), la convertit en WebP
     * et la stocke dans le dossier spécifié ($uploadDir).
     *
     * @param UploadedFile $file Fichier image uploadé via Symfony
     * @param string $uploadDir Dossier cible pour l’enregistrement
     * @return string URL publique de l’image WebP générée
     * @throws \Exception En cas d’erreur d’extension, d’upload ou de conversion
     */
    public static function uploadImage(UploadedFile $file, string $uploadDir): string
    {
    // Extensions autorisées
        $_registration_allowed_extensions = ['png', 'jpg', 'jpeg', 'webp'];

        // Extension du fichier
        $image_extension = $file->guessExtension();
        if (!in_array(strtolower($image_extension), $_registration_allowed_extensions)) {
            throw new \Exception("Extension de fichier non prise en charge.");
        }

        // Nom original (sans l’extension)
        $original_name = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
        $image_name = $original_name . '.' . $image_extension;
        $finalPath = $uploadDir . DIRECTORY_SEPARATOR . $image_name;

        // Éviter les collisions de nom
        $counter = 1;
        while (file_exists($finalPath)) {
            $image_name = $original_name . '_' . $counter . '.' . $image_extension;
            $finalPath = $uploadDir . DIRECTORY_SEPARATOR . $image_name;
            $counter++;
        }

        // Déplacement du fichier depuis le cache Symfony vers le répertoire cible
        $file->move($uploadDir, $image_name);

        // Vérification de l’existence réelle
        if (!file_exists($finalPath)) {
            throw new \Exception("Le fichier uploadé n'existe pas : " . $finalPath);
        }

        // Utilisation de ImageMagick pour convertir en WebP
        if (class_exists('Imagick')) {
            try {
                // Création d'un objet Imagick pour l'image téléchargée
                $imagick = new Imagick($finalPath);

                // Optimisation web : redimensionnement + qualité + strip métadonnées.
                // Sans ça les visuels back-office (slider, catégories…) étaient servis
                // en pleine résolution/qualité 100 → plusieurs centaines de Ko à 1 Mo.
                $maxWidth = 2000; // largeur max (couvre le hero pleine largeur en retina)
                if ($imagick->getImageWidth() > $maxWidth) {
                    // 0 en hauteur = ratio conservé
                    $imagick->resizeImage($maxWidth, 0, Imagick::FILTER_LANCZOS, 1);
                }
                $imagick->stripImage(); // retire EXIF/ICC inutiles

                // Conversion au format WebP
                $imagick->setImageFormat('webp');

                // Qualité 82 : compromis poids/rendu (quasi indiscernable de 100,
                // ~4 à 6× plus léger)
                $imagick->setImageCompressionQuality(82);

                // Définir le chemin de l'image WebP
                $webpPath = $uploadDir . DIRECTORY_SEPARATOR . $original_name . '.webp';
                
                // Sauvegarde de l'image convertie en WebP
                $imagick->writeImage($webpPath);
                
                // Libération des ressources
                $imagick->clear();
                
                // Suppression de l’image originale
                unlink($finalPath);
                
            } catch (\Exception $e) {
                throw new \Exception("Erreur de conversion avec Imagick: " . $e->getMessage());
            }
        } else {
            throw new \Exception("Imagick n'est pas installé sur le serveur.");
        }

        // Retourne l’URL publique de l’image WebP
        return __PS_BASE_URI__ . 'themes/presta_theme/assets/img/' . $original_name . '.webp';

    }




    /**
     * updateCssFile
     * 
     * Met à jour le fichier var.css avec les nouvelles variables de configuration
     * 
     */
    public static function updateCssFile(){

         $config = ConfigTheme::load();

        // Chemin vers le fichier var.css
        $fileVarCss = _PS_ROOT_DIR_ . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . 'presta_theme' . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'var.css';

        // Générer le contenu du fichier var.css avec les nouvelles variables
        $css = ':root{
            --primary: ' . ($config->configGeneral[0]->primary ?? '') . ';
            --secondary: ' . ($config->configGeneral[0]->secondary ?? '') . ';
            --PoliceTitle: "' . ($config->configGeneral[0]->fontTitle ?? '') . '";
            --PoliceText: "' . ($config->configGeneral[0]->fontText ?? '') . '";
            --HeaderBackground: ' . ($config->configHeader[0]->background ?? '') . ';
            --HeaderColor: ' . ($config->configHeader[0]->color ?? '') . ';
            --FooterBackground: ' . ($config->configFooter[0]->background ?? '') . ';
            --FooterColor: ' . ($config->configFooter[0]->color ?? '') . ';
            --BandeauBackground: ' . ($config->configTopBandeauParameter[0]->background ?? '') . ';
            --BandeauColor: ' . ($config->configTopBandeauParameter[0]->color ?? '') . ';
        };';

        
        
        // Sauvegarder le nouveau contenu dans le fichier var.css
        file_put_contents($fileVarCss, $css);

        // --- Thème MÉRIDIAN : var.css mappé sur les tokens du design system ---
        // On ne génère que les variables réellement renseignées en back-office ;
        // les autres retombent sur les valeurs par défaut définies dans theme.css.
        self::updateMeridianCssFile($config);
    }

    /**
     * updateMeridianCssFile
     *
     * Génère themes/meridian/assets/css/var.css en surchargeant les tokens MÉRIDIAN
     * avec les couleurs ET polices choisies par le client (principale/secondaire,
     * en-tête, footer, bandeau, police titres/textes). Une valeur vide = défaut du thème.
     */
    public static function updateMeridianCssFile(ConfigTheme $config): void
    {
        $g = $config->configGeneral[0] ?? null;
        $h = $config->configHeader[0] ?? null;
        $f = $config->configFooter[0] ?? null;
        $b = $config->configTopBandeauParameter[0] ?? null;

        // --- Polices ---
        // Fontes natives du thème, déjà déclarées (@font-face) dans theme.css : on ne les redéclare pas.
        $builtinFonts = ['Bodoni Moda', 'Archivo'];
        // Les autres polices sont des TTF servies depuis le thème presta_theme (toujours déployé par Install).
        $fontsUrl = __PS_BASE_URI__ . 'themes/presta_theme/assets/fonts/';
        $faces = '';
        $seen  = [];
        foreach ([$g?->fontTitle, $g?->fontText] as $family) {
            if (empty($family) || in_array($family, $builtinFonts, true) || isset($seen[$family])) {
                continue;
            }
            $seen[$family] = true;
            $faces .= "@font-face{font-family:'{$family}';font-display:swap;src:url('{$fontsUrl}{$family}-Regular.ttf') format('truetype');}\n";
            $faces .= "@font-face{font-family:'{$family}';font-style:italic;font-display:swap;src:url('{$fontsUrl}{$family}-Italic.ttf') format('truetype');}\n";
        }

        $fontDisplay = !empty($g?->fontTitle) ? "\"{$g->fontTitle}\", Georgia, \"Times New Roman\", serif" : null;
        $fontSans    = !empty($g?->fontText)  ? "\"{$g->fontText}\", system-ui, -apple-system, \"Segoe UI\", sans-serif" : null;

        // Largeur globale du site : 'full' => le contenu occupe toute la page
        // (max-width:none), sinon on retombe sur la largeur max par défaut du thème.
        $containerMax = (($g?->container ?? 'contained') === 'full') ? 'none' : null;

        // Mapping back-office -> token du thème MÉRIDIAN (theme.css)
        $map = [
            '--accent'        => $g?->primary,    // couleur principale (accents, CTA, liens, badges)
            '--ink'           => $g?->secondary,  // couleur secondaire (texte/éléments sombres) — garder une teinte foncée
            '--maxw'          => $containerMax,   // largeur du site : 'none' = pleine largeur ; null = défaut (contenu)
            '--font-display'  => $fontDisplay,    // police des titres
            '--font-sans'     => $fontSans,       // police des textes
            '--mrd-hdr-bg'    => $h?->background,  // fond de l'en-tête
            '--mrd-hdr-fg'    => $h?->color,       // texte de l'en-tête
            '--foot-bg'       => $f?->background,  // fond du footer
            '--foot-fg'       => $f?->color,       // texte du footer
            '--announce-bg'   => $b?->background,  // fond du bandeau
            '--announce-fg'   => $b?->color,       // texte du bandeau
        ];

        $lines = '';
        foreach ($map as $token => $value) {
            if (!empty($value)) {
                $lines .= "  {$token}: {$value};\n";
            }
        }

        $css = "/* Généré par le module — couleurs & polices personnalisées (back-office). Surcharge les tokens de theme.css. */\n{$faces}:root{\n{$lines}}\n";

        $fileVarCss = _PS_ROOT_DIR_ . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . 'meridian'
            . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'var.css';

        if (is_dir(dirname($fileVarCss))) {
            file_put_contents($fileVarCss, $css);
        }
    }


      public static function getShippingEstimator()
    {
       
        $config = ConfigTheme::load();
        $livraison = $config->configLivraison[0];

        // Current timestamp and hour
        $currentTimestamp = time();
        $currentHour = (int) date('G', $currentTimestamp); // Hour in 0–23

        // Get non-shipping days, delivery times per carrier, default carrier, and shipping cutoff hour
        $noShippingDays = $livraison->noShippingDays ?? [];
        $deliveryTimes = $livraison->deliveryTime ?? [];
        $defaultCarrier = $livraison->defaultCarrier ?? null;
        $shippingTime = (int) ($livraison->shippingTime ?? 0);

        // Map weekday names to numeric representation (0 = Sunday, 1 = Monday, …)
        $dayMapping = [
            'monday' => 1,
            'tuesday' => 2,
            'wednesday' => 3,
            'thursday' => 4,
            'friday' => 5,
            'saturday' => 6,
            'sunday' => 0,
        ];
        
            

        // Convert non-shipping days to numbers for easy comparison
        $noShippingDaysNumeric = array_map(
            function ($day) use ($dayMapping) {
                return $dayMapping[$day];
            },
            $noShippingDays
        );

        // Prepare arrays to store delivery dates
        $deliverys = [];
        $defaultDelivery = null;

        // Loop through each carrier and calculate its estimated delivery date
        foreach ($deliveryTimes as $carrierId => $deliveryTime) {
            $deliveryTime = (int) $deliveryTime;

            // ❗ If delivery time is 0, skip calculation and just return 0
            if ($deliveryTime === 0) {
                $deliverys[$carrierId] = 0;
                continue;
            }

           

            // 🔁 Start calculation from current timestamp for each carrier
            $currentTime = $currentTimestamp;
            $currentDay = (int) date('w', $currentTime);

            // If current hour exceeds shipping cutoff, push shipment to next day
            if ($currentHour >= $shippingTime) {
                $currentTime += 86400; // Add 1 day in seconds
                $currentDay = (int) date('w', $currentTime);
            }

            // Skip non-shipping days
            while (in_array($currentDay, $noShippingDaysNumeric, true)) {
                $currentTime += 86400; // Add 1 day
                $currentDay = (int) date('w', $currentTime);
            }

            // Estimated shipment date (after accounting for cutoff & no-shipping days)
            $expeditionDate = $currentTime;

            // Estimated delivery date = shipment date + delivery time in days
            $deliveryDate = $expeditionDate + ($deliveryTime * 86400);
            $deliveryDay = (int) date('w', $deliveryDate);


            // Skip non-shipping days for delivery as well
            while (in_array($deliveryDay, $noShippingDaysNumeric, true)) {
                $deliveryDate += 86400; // Add 1 day
                $deliveryDay = (int) date('w', $deliveryDate);
            }


            // Format the date based on language
            $formattedDate = date('d/m/Y', $deliveryDate); // DD/MM/YYYY 

            // Store the formatted date for this carrier
            $deliverys[$carrierId] = $formattedDate;

            // 📌 Store the delivery date for the default carrier
            if ((int) $carrierId === (int) $defaultCarrier) {
                $defaultDelivery = $formattedDate;
            }
        }

        // Return all the relevant shipping estimation data
        return [
            'delivery' => $defaultDelivery, // Date for default carrier
            'deliverys' => $deliverys,       // Dates for all carriers
            'shippingTime' => $shippingTime,    // Shipping cutoff hour
        ];
    }
    
 
}