/**
 * MissionGenerator.js
 * Factory that produces temporary Mission objects for Side Ops (procedural missions).
 * 
 * @typedef {import("../managers/types.js").MissionDefinition} MissionDefinition
 */

/**
 * MissionGenerator
 * Generates procedural side missions based on campaign tier and unlocked regions.
 */
export class MissionGenerator {
    /**
     * Adjectives for mission naming (general flavor)
     */
    static ADJECTIVES = [
        "Silent", "Broken", "Red", "Crimson", "Shattered", "Frozen", 
        "Burning", "Dark", "Blind", "Hidden", "Lost", "Ancient", "Hollow", "Swift"
    ];

    /**
     * Nouns for Skirmish (Combat) missions
     */
    static NOUNS_SKIRMISH = [
        "Thunder", "Storm", "Iron", "Fury", "Shield", "Hammer", 
        "Wrath", "Wall", "Strike", "Anvil"
    ];

    /**
     * Nouns for Salvage (Loot) missions
     */
    static NOUNS_SALVAGE = [
        "Cache", "Vault", "Echo", "Spark", "Core", "Grip", 
        "Harvest", "Trove", "Fragment", "Salvage"
    ];

    /**
     * Nouns for Assassination (Kill) missions
     */
    static NOUNS_ASSASSINATION = [
        "Viper", "Dagger", "Fang", "Night", "Shadow", "End", 
        "Hunt", "Razor", "Ghost", "Sting"
    ];

    /**
     * Nouns for Recon (Explore) missions
     */
    static NOUNS_RECON = [
        "Eye", "Watch", "Path", "Horizon", "Whisper", "Dawn", 
        "Light", "Step", "Vision", "Scope"
    ];

    /**
     * Tier configuration: [Name, Enemy Level Range, Reward Multiplier]
     */
    static TIER_CONFIG = {
        1: { name: "Recon", enemyLevel: [1, 2], multiplier: 1.0 },
        2: { name: "Patrol", enemyLevel: [3, 4], multiplier: 1.5 },
        3: { name: "Conflict", enemyLevel: [5, 6], multiplier: 2.5 },
        4: { name: "War", enemyLevel: [7, 8], multiplier: 4.0 },
        5: { name: "Suicide", enemyLevel: [9, 10], multiplier: 6.0 }
    };

    /**
     * Maps biome types to faction IDs for reputation rewards
     */
    static BIOME_TO_FACTION = {
        "BIOME_FUNGAL_CAVES": "ARCANE_DOMINION",
        "BIOME_RUSTING_WASTES": "COGWORK_CONCORD",
        "BIOME_CRYSTAL_SPIRES": "ARCANE_DOMINION",
        "BIOME_VOID_SEEP": "SHADOW_COVENANT",
        "BIOME_CONTESTED_FRONTIER": "IRON_LEGION"
    };

    /**
     * Converts a number to Roman numeral
     * @param {number} num - Number to convert (2-4)
     * @returns {string} Roman numeral
     */
    static toRomanNumeral(num) {
        const roman = ["", "I", "II", "III", "IV", "V"];
        return roman[num] || "";
    }

    /**
     * Extracts the base name (adjective + noun) from a mission title
     * @param {string} title - Mission title (e.g., "Operation: Silent Viper II")
     * @returns {string} Base name (e.g., "Silent Viper")
     */
    static extractBaseName(title) {
        // Remove "Operation: " prefix and any Roman numeral suffix
        const match = title.match(/Operation:\s*(.+?)(?:\s+[IVX]+)?$/);
        if (match) {
            return match[1].trim();
        }
        return title.replace(/Operation:\s*/, "").replace(/\s+[IVX]+$/, "").trim();
    }

    /**
     * Finds the highest Roman numeral in history for a given base name
     * @param {string} baseName - Base name (e.g., "Silent Viper")
     * @param {Array<string>} history - Array of completed mission titles or IDs
     * @returns {number} Highest numeral found (0 if none)
     */
    static findHighestNumeral(baseName, history) {
        let highest = 0;
        const pattern = new RegExp(`Operation:\\s*${baseName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s+([IVX]+)`, "i");
        
        for (const entry of history) {
            const match = entry.match(pattern);
            if (match) {
                const roman = match[1];
                const num = this.romanToNumber(roman);
                if (num > highest) {
                    highest = num;
                }
            }
        }
        
        return highest;
    }

    /**
     * Converts Roman numeral to number
     * @param {string} roman - Roman numeral string
     * @returns {number} Number value
     */
    static romanToNumber(roman) {
        const map = { "I": 1, "II": 2, "III": 3, "IV": 4, "V": 5 };
        return map[roman] || 0;
    }

    /**
     * Selects a random element from an array
     * @param {Array<T>} array - Array to select from
     * @returns {T} Random element
     * @template T
     */
    static randomChoice(array) {
        return array[Math.floor(Math.random() * array.length)];
    }

    /**
     * Generates a random number between min and max (inclusive)
     * @param {number} min - Minimum value
     * @param {number} max - Maximum value
     * @returns {number} Random number
     */
    static randomRange(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    /**
     * Generates a random float between min and max
     * @param {number} min - Minimum value
     * @param {number} max - Maximum value
     * @returns {number} Random float
     */
    static randomFloat(min, max) {
        return Math.random() * (max - min) + min;
    }

    /**
     * Selects a biome from unlocked regions with weighting
     * @param {Array<string>} unlockedRegions - Array of biome type IDs
     * @returns {string} Selected biome type
     */
    static selectBiome(unlockedRegions) {
        if (unlockedRegions.length === 0) {
            // Default fallback
            return "BIOME_RUSTING_WASTES";
        }

        // 40% chance for the most recently unlocked region (last in array)
        if (Math.random() < 0.4 && unlockedRegions.length > 0) {
            return unlockedRegions[unlockedRegions.length - 1];
        }

        // Otherwise random selection
        return this.randomChoice(unlockedRegions);
    }

    /**
     * Generates a Side Op mission
     * @param {number} tier - Campaign tier (1-5)
     * @param {Array<string>} unlockedRegions - Array of biome type IDs
     * @param {Array<string>} history - Array of completed mission titles or IDs
     * @returns {MissionDefinition} Generated mission object
     */
    static generateSideOp(tier, unlockedRegions, history = []) {
        // Validate tier
        const validTier = Math.max(1, Math.min(5, tier));
        const tierConfig = this.TIER_CONFIG[validTier];

        // Select archetype
        const archetypes = ["SKIRMISH", "SALVAGE", "ASSASSINATION", "RECON"];
        const archetype = this.randomChoice(archetypes);

        // Select noun based on archetype
        let noun;
        switch (archetype) {
            case "SKIRMISH":
                noun = this.randomChoice(this.NOUNS_SKIRMISH);
                break;
            case "SALVAGE":
                noun = this.randomChoice(this.NOUNS_SALVAGE);
                break;
            case "ASSASSINATION":
                noun = this.randomChoice(this.NOUNS_ASSASSINATION);
                break;
            case "RECON":
                noun = this.randomChoice(this.NOUNS_RECON);
                break;
            default:
                noun = this.randomChoice(this.NOUNS_SKIRMISH);
        }

        // Select adjective
        const adjective = this.randomChoice(this.ADJECTIVES);

        // Check history for series
        const baseName = `${adjective} ${noun}`;
        const highestNumeral = this.findHighestNumeral(baseName, history);
        const nextNumeral = highestNumeral + 1;
        const romanSuffix = nextNumeral > 1 ? ` ${this.toRomanNumeral(nextNumeral)}` : "";

        // Build title
        const title = `Operation: ${baseName}${romanSuffix}`;

        // Select biome
        const biomeType = this.selectBiome(unlockedRegions);

        // Generate objectives based on archetype
        const objectives = this.generateObjectives(archetype, validTier);

        // Generate biome config based on archetype
        const biomeConfig = this.generateBiomeConfig(archetype, biomeType);

        // Calculate rewards
        const rewards = this.calculateRewards(validTier, archetype, biomeType);

        // Generate unique ID (timestamp + random to ensure uniqueness)
        const missionId = `SIDE_OP_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;

        // Build mission object
        const mission = {
            id: missionId,
            type: "SIDE_QUEST",
            config: {
                title: title,
                description: this.generateDescription(archetype, biomeType),
                difficulty_tier: validTier,
                recommended_level: tierConfig.enemyLevel[1] // Use max enemy level as recommended
            },
            biome: biomeConfig,
            deployment: {
                squad_size_limit: 4
            },
            objectives: objectives,
            rewards: rewards,
            expiresIn: 3 // Expires in 3 campaign days
        };

        return mission;
    }

    /**
     * Generates objectives based on archetype
     * @param {string} archetype - Mission archetype
     * @param {number} tier - Difficulty tier
     * @returns {Object} Objectives object
     */
    static generateObjectives(archetype, tier) {
        switch (archetype) {
            case "SKIRMISH":
                return {
                    primary: [{
                        id: "OBJ_ELIMINATE_ALL",
                        type: "ELIMINATE_ALL",
                        description: "Clear the sector of hostile forces."
                    }],
                    failure_conditions: [{ type: "SQUAD_WIPE" }]
                };

            case "SALVAGE":
                const crateCount = this.randomRange(3, 5);
                return {
                    primary: [{
                        id: "OBJ_SALVAGE",
                        type: "INTERACT",
                        target_object_id: "OBJ_SUPPLY_CRATE",
                        target_count: crateCount,
                        description: `Recover ${crateCount} supply crates before the enemy secures them.`
                    }],
                    failure_conditions: [{ type: "SQUAD_WIPE" }]
                };

            case "ASSASSINATION":
                // Generate a random elite enemy ID
                const eliteEnemies = [
                    "ENEMY_ELITE_ECHO",
                    "ENEMY_ELITE_BREAKER",
                    "ENEMY_ELITE_STALKER",
                    "ENEMY_ELITE_WARDEN"
                ];
                const targetId = this.randomChoice(eliteEnemies);
                return {
                    primary: [{
                        id: "OBJ_HUNT",
                        type: "ELIMINATE_UNIT",
                        target_def_id: targetId,
                        description: "A High-Value Target has been spotted. Eliminate them."
                    }],
                    failure_conditions: [{ type: "SQUAD_WIPE" }]
                };

            case "RECON":
                // Generate 3 zone coordinates (simplified - actual zones would be set during mission generation)
                return {
                    primary: [{
                        id: "OBJ_RECON",
                        type: "REACH_ZONE",
                        target_count: 3,
                        description: "Survey the designated coordinates."
                    }],
                    failure_conditions: [
                        { type: "SQUAD_WIPE" },
                        { type: "TURN_LIMIT_EXCEEDED" }
                    ]
                };

            default:
                return {
                    primary: [{
                        id: "OBJ_DEFAULT",
                        type: "ELIMINATE_ALL",
                        description: "Complete the mission objectives."
                    }],
                    failure_conditions: [{ type: "SQUAD_WIPE" }]
                };
        }
    }

    /**
     * Generates biome configuration based on archetype
     * @param {string} archetype - Mission archetype
     * @param {string} biomeType - Biome type ID
     * @returns {Object} Biome configuration
     */
    static generateBiomeConfig(archetype, biomeType) {
        let size, roomCount, density;

        switch (archetype) {
            case "SKIRMISH":
                size = { x: 20, y: 12, z: 20 };
                roomCount = 6;
                density = "MEDIUM";
                break;

            case "SALVAGE":
                size = { x: 18, y: 12, z: 18 };
                roomCount = 5;
                density = "HIGH"; // High density for obstacles/cover
                break;

            case "ASSASSINATION":
                size = { x: 22, y: 12, z: 22 };
                roomCount = 7;
                density = "MEDIUM";
                break;

            case "RECON":
                size = { x: 24, y: 12, z: 24 }; // Large map
                roomCount = 8;
                density = "LOW"; // Low enemy density
                break;

            default:
                size = { x: 20, y: 12, z: 20 };
                roomCount = 6;
                density = "MEDIUM";
        }

        return {
            type: biomeType,
            generator_config: {
                seed_type: "RANDOM",
                size: size,
                room_count: roomCount,
                density: density
            }
        };
    }

    /**
     * Generates mission description based on archetype and biome
     * @param {string} archetype - Mission archetype
     * @param {string} biomeType - Biome type ID
     * @returns {string} Description text
     */
    static generateDescription(archetype, biomeType) {
        const biomeNames = {
            "BIOME_FUNGAL_CAVES": "Fungal Caves",
            "BIOME_RUSTING_WASTES": "Rusting Wastes",
            "BIOME_CRYSTAL_SPIRES": "Crystal Spires",
            "BIOME_VOID_SEEP": "Void Seep",
            "BIOME_CONTESTED_FRONTIER": "Contested Frontier"
        };
        const biomeName = biomeNames[biomeType] || "the region";

        switch (archetype) {
            case "SKIRMISH":
                return `Clear the sector of hostile forces in ${biomeName}.`;
            case "SALVAGE":
                return `Recover lost supplies before the enemy secures them in ${biomeName}.`;
            case "ASSASSINATION":
                return `A High-Value Target has been spotted in ${biomeName}. Eliminate them.`;
            case "RECON":
                return `Survey the designated coordinates in ${biomeName}.`;
            default:
                return `Complete the mission objectives in ${biomeName}.`;
        }
    }

    /**
     * Calculates rewards based on tier and archetype
     * @param {number} tier - Difficulty tier
     * @param {string} archetype - Mission archetype
     * @param {string} biomeType - Biome type ID
     * @returns {Object} Rewards object
     */
    static calculateRewards(tier, archetype, biomeType) {
        const tierConfig = this.TIER_CONFIG[tier];
        const multiplier = tierConfig.multiplier;

        // Base currency calculation: Base (50) * TierMultiplier * Random(0.8, 1.2)
        const baseCurrency = 50;
        const randomFactor = this.randomFloat(0.8, 1.2);
        const currencyAmount = Math.round(baseCurrency * multiplier * randomFactor);

        // XP calculation (base 100 * multiplier)
        const baseXP = 100;
        const xpAmount = Math.round(baseXP * multiplier * this.randomFloat(0.9, 1.1));

        // Assassination missions get bonus currency
        let finalCurrency = currencyAmount;
        if (archetype === "ASSASSINATION") {
            finalCurrency = Math.round(finalCurrency * 1.5);
        }

        // Items: 20% chance per Tier to drop a Chest Key or Item
        const items = [];
        const itemChance = tier * 0.2;
        if (Math.random() < itemChance) {
            // Randomly choose between chest key or item
            if (Math.random() < 0.5) {
                items.push("ITEM_CHEST_KEY");
            } else {
                // Generic item - would need item registry in real implementation
                items.push("ITEM_MATERIAL_SCRAP");
            }
        }

        // Reputation: +10 with the Region's owner
        const factionId = this.BIOME_TO_FACTION[biomeType] || "IRON_LEGION";
        const reputation = 10;

        const rewards = {
            guaranteed: {
                xp: xpAmount,
                currency: {
                    aether_shards: finalCurrency
                }
            },
            faction_reputation: {
                [factionId]: reputation
            }
        };

        // Add items if any
        if (items.length > 0) {
            rewards.guaranteed.items = items;
        }

        return rewards;
    }

    /**
     * Refreshes the mission board, filling it up to 5 entries and removing expired missions
     * @param {Array<MissionDefinition>} currentMissions - Current list of available missions
     * @param {number} tier - Current campaign tier
     * @param {Array<string>} unlockedRegions - Array of unlocked biome type IDs
     * @param {Array<string>} history - Array of completed mission titles or IDs
     * @param {boolean} isDailyReset - If true, decrements expiresIn for all missions
     * @returns {Array<MissionDefinition>} Updated mission list
     */
    static refreshBoard(currentMissions = [], tier, unlockedRegions, history = [], isDailyReset = false) {
        // On daily reset, decrement expiresIn for all missions
        let validMissions = currentMissions;
        if (isDailyReset) {
            validMissions = currentMissions.map(mission => {
                if (mission.expiresIn !== undefined) {
                    const updated = { ...mission };
                    updated.expiresIn = (mission.expiresIn || 3) - 1;
                    return updated;
                }
                return mission;
            });
        }

        // Remove missions that have expired (expiresIn <= 0)
        validMissions = validMissions.filter(mission => {
            if (mission.expiresIn !== undefined) {
                return mission.expiresIn > 0;
            }
            // Keep missions without expiration tracking
            return true;
        });

        // Fill up to 5 missions
        const targetCount = 5;
        const needed = Math.max(0, targetCount - validMissions.length);

        const newMissions = [];
        for (let i = 0; i < needed; i++) {
            const mission = this.generateSideOp(tier, unlockedRegions, history);
            newMissions.push(mission);
        }

        // Combine and return
        return [...validMissions, ...newMissions];
    }
}

