/**
 * TravelDistanceV2
 * Classe de gestion du calcul des distances de voyage pour WFRP4e
 * Version adaptée pour le module de traduction française
 */
import { PathFinder } from './pathfinding.js';

export default class TravelDistanceV2 {
    static roadGraph = null; // Graphe pour les routes terrestres uniquement
    static waterGraph = null; // Graphe pour les voies fluviales et maritimes
    static mixedGraph = null; // Graphe combinant tous les modes de transport

    /**
     * Charge les données de voyage depuis le fichier JSON
     */
    static async loadTravelData() {
        try {
            console.log("TravelV2: Début du chargement des données...");
            const response = await fetch('modules/wh4-fr-translation/modules/travelv2/travel_data.json');

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            this.travel_data = await response.json();
            console.log(`TravelV2: ${this.travel_data.length} routes chargées avec succès`);

            // Construire les 3 graphes pour le pathfinding
            this.roadGraph = PathFinder.buildGraph(this.travel_data, 'road');
            this.waterGraph = PathFinder.buildGraph(this.travel_data, 'water');
            this.mixedGraph = PathFinder.buildGraph(this.travel_data, 'mixed');

            console.log(`TravelV2: Graphe routier: ${Object.keys(this.roadGraph).length} villes`);
            console.log(`TravelV2: Graphe fluvial/maritime: ${Object.keys(this.waterGraph).length} villes`);
            console.log(`TravelV2: Graphe mixte: ${Object.keys(this.mixedGraph).length} villes`);

            ui.notifications.info(`TravelV2: ${this.travel_data.length} routes de voyage chargées`);
        } catch (error) {
            console.error("TravelV2: Erreur lors du chargement des données de voyage:", error);
            ui.notifications.error("Erreur lors du chargement des données de voyage. Vérifiez la console.");
            this.travel_data = []; // Initialiser avec un tableau vide pour éviter les erreurs
        }
    }

    /**
     * Retourne une chaîne lisible pour le niveau de danger
     * @param {String} dangerLevel
     * @returns {String}
     */
    static dangerToString(dangerLevel) {
        if (dangerLevel == "") return "Très bas";
        if (dangerLevel == '!') return "Bas";
        if (dangerLevel == '!!') return "Moyen";
        if (dangerLevel == '!!!') return "Élevé";
        return "Très élevé";
    }

    /**
     * Arrondit la durée à une valeur entière ou .5
     * @param {Number} duration
     * @returns {Number}
     */
    static roundDuration(duration) {
        let trunc = Math.trunc(duration);
        let frac = duration - trunc;
        let adjust = 0;
        if (frac > 0.75) adjust = 1;
        else if (frac >= 0.25) adjust = 0.5;
        return trunc + adjust;
    }

    /**
     * Affiche les distances de voyage entre deux villes ou liste les destinations
     * @param {String} fromTown Ville de départ
     * @param {String} toTown Ville d'arrivée (optionnel)
     */
    static displayTravelDistance(fromTown, toTown) {
        // Vérifier que les données sont chargées
        if (!this.travel_data || this.travel_data.length === 0) {
            ui.notifications.error("Les données de voyage ne sont pas encore chargées. Veuillez patienter...");
            console.error("TravelV2: travel_data n'est pas chargé");
            return;
        }

        console.log(`TravelV2: displayTravelDistance appelé avec fromTown="${fromTown}", toTown="${toTown}"`);
        console.log(`TravelV2: fromTown type: ${typeof fromTown}, valeur falsy: ${!fromTown}`);
        console.log(`TravelV2: toTown type: ${typeof toTown}, valeur falsy: ${!toTown}`);
        console.log(`TravelV2: ${this.travel_data.length} routes disponibles`);

        let message = "";

        console.log("TravelV2: Vérification des conditions...");
        console.log(`TravelV2: toTown ? ${!!toTown}`);
        console.log(`TravelV2: fromTown == 'help' ? ${fromTown == 'help'}`);
        console.log(`TravelV2: fromTown ? ${!!fromTown}`);
        console.log(`TravelV2: else (pas de fromTown) ? ${!fromTown && !toTown}`);

        if (toTown) {
            console.log("TravelV2: Branche: Affichage des détails entre deux villes");
            // Afficher les détails de voyage entre deux villes spécifiques
            const originalFrom = fromTown;
            const originalTo = toTown;
            fromTown = fromTown.toLowerCase();
            toTown = toTown.toLowerCase();

            // Chercher d'abord une route directe
            let directRoute = null;
            for (const travel of this.travel_data) {
                if (travel.from.toLowerCase() == fromTown && travel.to.toLowerCase() == toTown) {
                    directRoute = travel;
                    break;
                }
            }

            if (directRoute) {
                // Route directe trouvée - affichage classique avec toutes les options
                message += this.formatDirectRoute(directRoute);
            } else {
                // Pas de route directe - calculer les 3 types de trajets
                console.log("TravelV2: Pas de route directe, calcul des itinéraires...");

                const mixedPath = PathFinder.dijkstra(this.mixedGraph, originalFrom, originalTo, 'days');
                const roadPath = PathFinder.dijkstra(this.roadGraph, originalFrom, originalTo, 'days');
                const waterPath = PathFinder.dijkstra(this.waterGraph, originalFrom, originalTo, 'days');

                if (!mixedPath && !roadPath && !waterPath) {
                    message += `<p><strong>Aucun chemin trouvé entre ${originalFrom} et ${originalTo}</strong></p>`;
                    message += `<p>Il n'existe pas de route reliant ces deux villes dans les données disponibles.</p>`;
                } else {
                    message += `<div class="voyage-main-title">De ${originalFrom} à ${originalTo}</div>`;
                    message += `<p><em>Différentes options de voyage disponibles :</em></p><hr class="voyage-separator">`;

                    // Option 1 : Trajet mixte optimal (le plus rapide)
                    if (mixedPath) {
                        message += this.formatMultiStepRoute(mixedPath, originalFrom, originalTo, 'mixed');
                        message += `<hr class="voyage-separator">`;
                    }

                    // Option 2 : Trajet 100% terrestre
                    if (roadPath) {
                        message += this.formatMultiStepRoute(roadPath, originalFrom, originalTo, 'road');
                        message += `<hr class="voyage-separator">`;
                    }

                    // Option 3 : Trajet 100% eau (fleuve/mer)
                    if (waterPath) {
                        message += this.formatMultiStepRoute(waterPath, originalFrom, originalTo, 'water');
                    }
                }
            }

            // Bouton pour enregistrer dans le journal
            message += this.formatJournalButton(originalFrom, originalTo);
        } else if (fromTown && fromTown == "help") {
            console.log("TravelV2: Branche: Affichage de l'aide");
            // Afficher l'aide
            message += `<p><strong>Aide pour /voyage</strong><br>`;
            message += `Usage: <code>/voyage [ville_départ] [ville_arrivée]</code><br><br>`;
            message += `Exemples:<br>`;
            message += `<code>/voyage</code> - Liste toutes les villes de départ<br>`;
            message += `<code>/voyage Altdorf</code> - Liste les destinations depuis Altdorf<br>`;
            message += `<code>/voyage Altdorf Nuln</code> - Affiche les détails de voyage entre Altdorf et Nuln`;
            message += `</p>`;
        } else if (fromTown) {
            console.log("TravelV2: Branche: Liste des destinations depuis une ville");
            // Lister toutes les destinations possibles depuis une ville (avec pathfinding)
            const normalizedFrom = PathFinder.findCityInGraph(this.roadGraph, fromTown);

            if (normalizedFrom) {
                message += `<div class="voyage-destinations-title">Destinations depuis ${normalizedFrom}</div>`;
                message += `<p><em>Toutes les villes accessibles (routes directes et itinéraires calculés)</em></p>`;

                // Récupérer toutes les villes du graphe sauf la ville de départ
                const allCities = Object.keys(this.roadGraph)
                    .filter(city => city.toLowerCase() !== normalizedFrom.toLowerCase())
                    .sort((a, b) => a.localeCompare(b));

                // Afficher toutes les destinations
                for (const city of allCities) {
                    message += `<p><a class="action-link" data-action="clickVoyage" data-from="${normalizedFrom}" data-to="${city}"><i class="fas fa-map-marked-alt"></i> ${city}</a></p>`;
                }
            } else {
                message += `<p><strong>Ville inconnue: ${fromTown}</strong></p>`;
                message += `<p>Cette ville n'existe pas dans la base de données.</p>`;
            }
        } else {
            console.log("TravelV2: Branche: Liste de toutes les villes de départ");
            // Lister toutes les villes de départ
            message += `<div class="voyage-destinations-title">Sélectionnez une ville de départ</div>`;
            let uniqTown = {};

            for (const travel of this.travel_data) {
                if (uniqTown[travel.from] == undefined) {
                    uniqTown[travel.from] = 1;
                    message += `<p><a class="action-link" data-action="clickVoyage" data-from="${travel.from}"><i class="fas fa-list"></i> ${travel.from}</a></p>`;
                }
            }
        }

        console.log(`TravelV2: Message généré (longueur: ${message.length})`);

        if (message.length === 0) {
            console.warn("TravelV2: Aucune donnée trouvée pour les critères fournis");
            ui.notifications.warn("Aucune route trouvée pour ces critères");
            return;
        }

        ChatMessage.create({
            content: message,
            whisper: [game.user.id],  // Afficher uniquement pour le GM qui a lancé la commande
            speaker: { alias: "Outil de voyage" }
        });

        console.log("TravelV2: ChatMessage créé avec succès");
    }

    /**
     * Gère le clic sur un lien de voyage
     * @param {Event} event
     * @param {HTMLElement} target
     */
    static handleTravelClick(event, target) {
        let fromTown = target.dataset.from;
        let toTown = target.dataset.to;
        TravelDistanceV2.displayTravelDistance(fromTown, toTown);
    }

    /**
     * Retourne le HTML du bouton "Enregistrer dans le journal"
     * @param {String} from - Ville de départ
     * @param {String} to - Ville d'arrivée
     * @returns {String} HTML du bouton
     */
    static formatJournalButton(from, to) {
        return `<div class="voyage-journal-action" style="margin-top:8px;text-align:right">
            <button type="button" class="voyage-journal-btn" data-action="saveVoyageToJournal"
                data-from="${from}" data-to="${to}">
                <i class="fas fa-book"></i> Enregistrer dans le journal "Voyages"
            </button>
        </div>`;
    }

    /**
     * Enregistre le contenu d'un voyage dans le journal FoundryVTT "Voyages"
     * @param {String} from - Ville de départ
     * @param {String} to - Ville d'arrivée
     * @param {String} content - HTML complet du message de tchat
     */
    static async saveVoyageToJournal(from, to, content) {
        if (!game.user.isGM) {
            ui.notifications.warn("Seul le MJ peut enregistrer dans le journal.");
            return;
        }

        const journalName = "Voyages";
        let journal = game.journal.find(j => j.name === journalName);
        if (!journal) {
            journal = await JournalEntry.create({ name: journalName });
        }

        // Supprimer le bouton du contenu avant de l'enregistrer
        const parser = new DOMParser();
        const doc = parser.parseFromString(content, 'text/html');
        doc.querySelectorAll('.voyage-journal-action').forEach(el => el.remove());
        const cleanContent = doc.body.innerHTML;

        const now = new Date();
        const dateStr = now.toLocaleDateString('fr-FR');
        const pageName = `${from} → ${to} (${dateStr})`;

        await journal.createEmbeddedDocuments("JournalEntryPage", [{
            name: pageName,
            type: "text",
            text: {
                content: cleanContent,
                format: CONST.JOURNAL_ENTRY_PAGE_FORMATS.HTML
            }
        }]);

        // Ouvrir le journal sur la nouvelle page
        const page = journal.pages.find(p => p.name === pageName);
        journal.sheet.render(true, { pageId: page?.id });
        ui.notifications.info(`Voyage "${from} → ${to}" enregistré dans le journal.`);
    }

    /**
     * Formate l'affichage d'une route directe
     * @param {Object} travel - Données de la route
     * @returns {String} HTML formaté
     */
    static formatDirectRoute(travel) {
        let message = `<p><strong>De ${travel.from} à ${travel.to}</strong> (Route directe)`;

        if (travel.road_distance != "") {
            let road_horse_heavy_days = this.roundDuration(travel.road_days * 0.8);
            let road_horse_fast_days = this.roundDuration(travel.road_days * 0.65);
            let road_feet_days = this.roundDuration(travel.road_days * 1.25);
            let road_danger_string = this.dangerToString(travel.road_danger);
            let road_danger_feet_string = this.dangerToString(travel.road_danger + "!");

            message += `<br><br><strong>Par route:</strong>`;
            message += `<br>Distance: ${travel.road_distance} km`;
            message += `<br>Durée (chariot): ${travel.road_days} jours - Danger: ${road_danger_string}`;
            message += `<br>Durée (cheval de charge): ${road_horse_heavy_days} jours - Danger: ${road_danger_string}`;
            message += `<br>Durée (cheval rapide): ${road_horse_fast_days} jours - Danger: ${road_danger_string}`;
            message += `<br>Durée (à pied): ${road_feet_days} jours - Danger: ${road_danger_feet_string}`;
        }

        if (travel.river_distance != "") {
            let river_danger_string = this.dangerToString(travel.river_danger);
            message += `<br><br><strong>Par rivière:</strong>`;
            message += `<br>Distance: ${travel.river_distance} km`;
            message += `<br>Durée: ${travel.river_days} jours - Danger: ${river_danger_string}`;
        }

        if (travel.sea_distance != "") {
            let sea_danger_string = this.dangerToString(travel.sea_danger);
            message += `<br><br><strong>Par mer:</strong>`;
            message += `<br>Distance: ${travel.sea_distance} km`;
            message += `<br>Durée: ${travel.sea_days} jours - Danger: ${sea_danger_string}`;
        }

        message += "</p>";
        return message;
    }

    /**
     * Formate l'affichage d'une route multi-étapes
     * @param {Object} pathResult - Résultat du pathfinding
     * @param {String} fromCity - Ville de départ
     * @param {String} toCity - Ville d'arrivée
     * @param {String} routeType - Type de route ('mixed', 'road', 'water')
     * @returns {String} HTML formaté
     */
    static formatMultiStepRoute(pathResult, fromCity, toCity, routeType = 'road') {
        // Déterminer le titre selon le type
        let routeTitle = "";

        if (routeType === 'mixed') {
            routeTitle = "🌟 Itinéraire optimal (tous modes de transport)";
        } else if (routeType === 'road') {
            routeTitle = "🛤️ Itinéraire 100% terrestre";
        } else if (routeType === 'water') {
            routeTitle = "⛵ Itinéraire 100% fluvial/maritime";
        }

        let message = `<div class="voyage-route-title">${routeTitle}</div>`;
        message += `<p><strong>${fromCity} → ${toCity}</strong> (${pathResult.steps} étape${pathResult.steps > 1 ? 's' : ''})`;

        // Résumé du voyage
        const totalDistance = Math.round(pathResult.totalDistance);
        const totalDays = Math.round(pathResult.totalDays);
        const danger_string = this.dangerToString(pathResult.maxDanger);

        // Pour les routes terrestres, afficher les variantes de durée
        const includesRoad = !pathResult.modesUsed || pathResult.modesUsed.includes('road');

        message += `<br><br><strong>📊 Résumé du voyage:</strong>`;
        message += `<br>Distance totale: ${totalDistance} km`;

        if (includesRoad) {
            const road_horse_heavy_days = this.roundDuration(pathResult.totalDays * 0.8);
            const road_horse_fast_days = this.roundDuration(pathResult.totalDays * 0.65);
            const road_feet_days = this.roundDuration(pathResult.totalDays * 1.25);
            const danger_feet_string = this.dangerToString(pathResult.maxDanger + "!");

            message += `<br>Durée (chariot): ${totalDays} jours - Danger max: ${danger_string}`;
            message += `<br>Durée (cheval de charge): ${road_horse_heavy_days} jours - Danger max: ${danger_string}`;
            message += `<br>Durée (cheval rapide): ${road_horse_fast_days} jours - Danger max: ${danger_string}`;
            message += `<br>Durée (à pied): ${road_feet_days} jours - Danger max: ${danger_feet_string}`;
        } else {
            message += `<br>Durée totale: ${totalDays} jours - Danger max: ${danger_string}`;
        }

        // Détails des étapes avec mode de transport
        message += `<br><br><strong>🗺️ Itinéraire détaillé:</strong>`;
        for (let i = 0; i < pathResult.path.length; i++) {
            const step = pathResult.path[i];
            const stepNum = i + 1;
            const stepDanger = this.dangerToString(step.danger);

            // Icône selon le mode de transport
            let modeIcon = "🛤️";
            let modeName = "route";
            if (step.mode === 'river') {
                modeIcon = "🚣";
                modeName = "fleuve";
            } else if (step.mode === 'sea') {
                modeIcon = "⛵";
                modeName = "mer";
            }

            message += `<br><br><em>Étape ${stepNum}:</em> ${step.from} → ${step.to}`;
            message += `<br>  ${modeIcon} Par ${modeName}: ${Math.round(step.distance)} km, ${step.days} jour${step.days > 1 ? 's' : ''} - Danger: ${stepDanger}`;
        }

        message += "</p>";
        return message;
    }
}
