/*
 * File: D:\shadowed-realms-mobile\ShadowedRealmsMobile\src\server\ShadowedRealms.API\Services\CombatCalculationEngine.cs
 * Created: 2025-10-30
 * Last Modified: 2025-10-30
 * Description: Complete statistical combat calculation engine for Attack/Defense/Health system with configurable balance, rally mechanics, hospital cascade, and troop tier priority
 * Last Edit Notes: Full implementation of combat calculation engine with all discussed features including Standard/Mega rallies, hospital cascade system, and configurable combat balance
 */

using ShadowedRealms.Core.Models;
using ShadowedRealms.Shared.DTOs.Combat;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace ShadowedRealms.API.Services
{
    /// <summary>
    /// Complete combat calculation engine handling all statistical combat mechanics
    /// </summary>
    public class CombatCalculationEngine
    {
        private readonly IConfiguration _configuration;
        private readonly ILogger<CombatCalculationEngine> _logger;
        private readonly Random _random;

        public CombatCalculationEngine(
            IConfiguration configuration,
            ILogger<CombatCalculationEngine> logger)
        {
            _configuration = configuration;
            _logger = logger;
            _random = new Random();
        }

        #region Combat Balance Configuration

        /// <summary>
        /// Gets configurable combat balance settings
        /// </summary>
        private CombatBalanceConfig GetCombatBalance()
        {
            return new CombatBalanceConfig
            {
                // RNG and Variance Settings
                RngVariancePercentage = _configuration.GetValue<decimal>("Combat:RngVariancePercentage", 0.15m),
                CriticalEventChance = _configuration.GetValue<decimal>("Combat:CriticalEventChance", 0.02m),
                DragonSkillActivationChance = _configuration.GetValue<decimal>("Combat:DragonSkillActivationChance", 0.15m),

                // Hospital System Settings
                BaseWoundedPercentage = _configuration.GetValue<decimal>("Combat:Hospital:BaseWoundedPercentage", 0.70m),
                BaseKilledPercentage = _configuration.GetValue<decimal>("Combat:Hospital:BaseKilledPercentage", 0.30m),
                SanctumBasePercentage = _configuration.GetValue<decimal>("Combat:Hospital:SanctumBasePercentage", 0.70m),
                SanctumVipBonus = _configuration.GetValue<decimal>("Combat:Hospital:SanctumVipBonus", 0.10m),
                SanctumSubscriptionBonus = _configuration.GetValue<decimal>("Combat:Hospital:SanctumSubscriptionBonus", 0.10m),
                SanctumCapacityMultiplier = _configuration.GetValue<decimal>("Combat:Hospital:SanctumCapacityMultiplier", 4.0m),

                // Troop Tier Multipliers (configurable scaling)
                TroopTierMultipliers = GetTroopTierMultipliers(),

                // Base Troop Stats (configurable by type)
                BaseTroopStats = GetBaseTroopStats(),

                // Field Interception Bonuses
                FieldInterceptionDefenseBonus = _configuration.GetValue<decimal>("Combat:FieldInterception:DefenseBonus", 0.15m),
                FieldInterceptionAttackBonus = _configuration.GetValue<decimal>("Combat:FieldInterception:AttackBonus", 0.05m),
                FieldInterceptionAttackerPenalty = _configuration.GetValue<decimal>("Combat:FieldInterception:AttackerPenalty", 0.05m)
            };
        }

        /// <summary>
        /// Gets configurable troop tier multipliers
        /// </summary>
        private Dictionary<int, decimal> GetTroopTierMultipliers()
        {
            var multipliers = new Dictionary<int, decimal>();
            for (int tier = 1; tier <= 15; tier++) // Support up to T15 for future expansion
            {
                var configKey = $"Combat:TroopTiers:T{tier}Multiplier";
                var defaultValue = (decimal)Math.Pow(1.5, tier - 1); // Exponential scaling as default
                multipliers[tier] = _configuration.GetValue<decimal>(configKey, defaultValue);
            }
            return multipliers;
        }

        /// <summary>
        /// Gets configurable base troop stats by type
        /// </summary>
        private Dictionary<string, TroopBaseStats> GetBaseTroopStats()
        {
            return new Dictionary<string, TroopBaseStats>
            {
                ["Infantry"] = new TroopBaseStats
                {
                    BaseAttack = _configuration.GetValue<decimal>("Combat:TroopStats:Infantry:BaseAttack", 100m),
                    BaseDefense = _configuration.GetValue<decimal>("Combat:TroopStats:Infantry:BaseDefense", 120m),
                    BaseHealth = _configuration.GetValue<decimal>("Combat:TroopStats:Infantry:BaseHealth", 150m)
                },
                ["Cavalry"] = new TroopBaseStats
                {
                    BaseAttack = _configuration.GetValue<decimal>("Combat:TroopStats:Cavalry:BaseAttack", 130m),
                    BaseDefense = _configuration.GetValue<decimal>("Combat:TroopStats:Cavalry:BaseDefense", 100m),
                    BaseHealth = _configuration.GetValue<decimal>("Combat:TroopStats:Cavalry:BaseHealth", 140m)
                },
                ["Bowmen"] = new TroopBaseStats
                {
                    BaseAttack = _configuration.GetValue<decimal>("Combat:TroopStats:Bowmen:BaseAttack", 140m),
                    BaseDefense = _configuration.GetValue<decimal>("Combat:TroopStats:Bowmen:BaseDefense", 90m),
                    BaseHealth = _configuration.GetValue<decimal>("Combat:TroopStats:Bowmen:BaseHealth", 120m)
                },
                ["Siege"] = new TroopBaseStats
                {
                    BaseAttack = _configuration.GetValue<decimal>("Combat:TroopStats:Siege:BaseAttack", 200m),
                    BaseDefense = _configuration.GetValue<decimal>("Combat:TroopStats:Siege:BaseDefense", 80m),
                    BaseHealth = _configuration.GetValue<decimal>("Combat:TroopStats:Siege:BaseHealth", 100m)
                }
            };
        }

        #endregion

        #region Main Combat Calculation Methods

        /// <summary>
        /// Calculates complete battle statistics for players
        /// </summary>
        public Dictionary<string, object> CalculateBattleStats(
            int attackerId,
            int defenderId,
            Dictionary<string, Dictionary<string, int>> attackerTroops,
            Dictionary<string, Dictionary<string, int>> defenderTroops,
            Dictionary<string, decimal> attackerBonuses,
            Dictionary<string, decimal> defenderBonuses,
            bool isFieldInterception = false,
            bool isMegaRally = false,
            Dictionary<string, decimal>? rallyLeaderBonuses = null)
        {
            try
            {
                var balance = GetCombatBalance();

                // Calculate effective stats for each side
                var attackerStats = CalculateEffectiveStats(
                    attackerTroops,
                    isMegaRally ? rallyLeaderBonuses ?? attackerBonuses : attackerBonuses,
                    balance);

                var defenderStats = CalculateEffectiveStats(
                    defenderTroops,
                    defenderBonuses,
                    balance);

                // Apply field interception modifiers
                if (isFieldInterception)
                {
                    ApplyFieldInterceptionModifiers(attackerStats, defenderStats, balance);
                }

                // Calculate power scores
                var attackerPower = CalculateTotalPowerScore(attackerStats, attackerTroops);
                var defenderPower = CalculateTotalPowerScore(defenderStats, defenderTroops);

                // Calculate win probability
                var winProbability = CalculateWinProbability(attackerPower, defenderPower);

                return new Dictionary<string, object>
                {
                    ["AttackerStats"] = attackerStats,
                    ["DefenderStats"] = defenderStats,
                    ["AttackerPower"] = attackerPower,
                    ["DefenderPower"] = defenderPower,
                    ["AttackerWinProbability"] = winProbability,
                    ["DefenderWinProbability"] = 1.0m - winProbability,
                    ["IsFieldInterception"] = isFieldInterception,
                    ["IsMegaRally"] = isMegaRally,
                    ["CalculationTime"] = DateTime.UtcNow
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to calculate battle stats for attacker {AttackerId} vs defender {DefenderId}",
                    attackerId, defenderId);
                throw;
            }
        }

        /// <summary>
        /// Executes complete statistical combat resolution
        /// </summary>
        public Dictionary<string, object> ExecuteStatisticalCombat(
            Dictionary<string, object> battleStats,
            Dictionary<string, Dictionary<string, int>> attackerTroops,
            Dictionary<string, Dictionary<string, int>> defenderTroops,
            bool hasDragon = false,
            List<string>? dragonSkills = null)
        {
            try
            {
                var balance = GetCombatBalance();
                var attackerWinProbability = (decimal)battleStats["AttackerWinProbability"];

                // Apply RNG variance
                var rngModifier = ApplyRngVariance(balance.RngVariancePercentage);
                var adjustedWinProbability = Math.Max(0.05m, Math.Min(0.95m, attackerWinProbability + rngModifier));

                // Determine battle outcome
                var attackerWins = _random.NextDecimal() < adjustedWinProbability;

                // Check for critical events
                var criticalEvent = CheckForCriticalEvents(balance.CriticalEventChance);
                var dragonSkillActivated = hasDragon ? CheckForDragonSkillActivation(balance.DragonSkillActivationChance, dragonSkills) : null;

                // Calculate casualties with tier priority
                var casualties = CalculateBattleCasualtiesWithTierPriority(
                    attackerTroops,
                    defenderTroops,
                    attackerWins,
                    adjustedWinProbability,
                    criticalEvent,
                    dragonSkillActivated,
                    balance);

                return new Dictionary<string, object>
                {
                    ["AttackerWins"] = attackerWins,
                    ["AttackerCasualties"] = casualties["AttackerCasualties"],
                    ["DefenderCasualties"] = casualties["DefenderCasualties"],
                    ["CriticalEvent"] = criticalEvent,
                    ["DragonSkillActivated"] = dragonSkillActivated,
                    ["ActualWinProbability"] = adjustedWinProbability,
                    ["RngModifier"] = rngModifier,
                    ["BattleDuration"] = TimeSpan.FromMinutes(3), // Fast-paced combat
                    ["BattleTime"] = DateTime.UtcNow
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to execute statistical combat");
                throw;
            }
        }

        /// <summary>
        /// Calculates battle casualties with hospital cascade system
        /// </summary>
        public Dictionary<string, object> CalculateBattleCasualties(
            Dictionary<string, object> combatResult,
            Dictionary<string, Dictionary<string, int>> attackerTroops,
            Dictionary<string, Dictionary<string, int>> defenderTroops,
            int attackerHospitalCapacity,
            int defenderHospitalCapacity,
            int attackerAllianceHospitalCapacity,
            int defenderAllianceHospitalCapacity,
            bool attackerHasVip10 = false,
            bool defenderHasVip10 = false,
            bool attackerHasSubscription = false,
            bool defenderHasSubscription = false)
        {
            try
            {
                var balance = GetCombatBalance();

                var attackerCasualties = (Dictionary<string, Dictionary<string, int>>)combatResult["AttackerCasualties"];
                var defenderCasualties = (Dictionary<string, Dictionary<string, int>>)combatResult["DefenderCasualties"];

                // Process hospital cascade for attacker
                var attackerHospitalResult = ProcessHospitalCascade(
                    attackerCasualties,
                    attackerHospitalCapacity,
                    attackerAllianceHospitalCapacity,
                    attackerHasVip10,
                    attackerHasSubscription,
                    balance);

                // Process hospital cascade for defender
                var defenderHospitalResult = ProcessHospitalCascade(
                    defenderCasualties,
                    defenderHospitalCapacity,
                    defenderAllianceHospitalCapacity,
                    defenderHasVip10,
                    defenderHasSubscription,
                    balance);

                return new Dictionary<string, object>
                {
                    ["AttackerHospitalResult"] = attackerHospitalResult,
                    ["DefenderHospitalResult"] = defenderHospitalResult,
                    ["TotalAttackerLosses"] = attackerHospitalResult["TotalKilled"],
                    ["TotalDefenderLosses"] = defenderHospitalResult["TotalKilled"],
                    ["HospitalProcessingTime"] = DateTime.UtcNow
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to calculate battle casualties with hospital cascade");
                throw;
            }
        }

        #endregion

        #region Rally System Implementation

        /// <summary>
        /// Processes Standard Rally (6 participants max, each uses own stats)
        /// </summary>
        public Dictionary<string, object> ProcessStandardRally(
            int rallyLeaderId,
            List<int> participantIds,
            Dictionary<int, Dictionary<string, Dictionary<string, int>>> participantTroops,
            Dictionary<int, Dictionary<string, decimal>> participantBonuses,
            int targetId,
            Dictionary<string, Dictionary<string, int>> defenderTroops,
            Dictionary<string, decimal> defenderBonuses)
        {
            try
            {
                if (participantIds.Count > 6)
                {
                    throw new InvalidOperationException("Standard rally limited to 6 participants maximum");
                }

                var rallyResults = new List<Dictionary<string, object>>();

                // Each participant fights individually but results are combined
                foreach (var participantId in participantIds)
                {
                    var battleStats = CalculateBattleStats(
                        participantId,
                        targetId,
                        participantTroops[participantId],
                        defenderTroops,
                        participantBonuses[participantId],
                        defenderBonuses);

                    var combatResult = ExecuteStatisticalCombat(
                        battleStats,
                        participantTroops[participantId],
                        defenderTroops,
                        false); // Individual dragon handling

                    rallyResults.Add(new Dictionary<string, object>
                    {
                        ["ParticipantId"] = participantId,
                        ["BattleStats"] = battleStats,
                        ["CombatResult"] = combatResult
                    });
                }

                return new Dictionary<string, object>
                {
                    ["RallyType"] = "Standard",
                    ["RallyLeaderId"] = rallyLeaderId,
                    ["ParticipantCount"] = participantIds.Count,
                    ["IndividualResults"] = rallyResults,
                    ["CombinedOutcome"] = CombineRallyResults(rallyResults),
                    ["RallyTime"] = DateTime.UtcNow
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to process standard rally led by {RallyLeaderId}", rallyLeaderId);
                throw;
            }
        }

        /// <summary>
        /// Processes Mega Rally (unlimited participants, leader stats apply to all)
        /// </summary>
        public Dictionary<string, object> ProcessMegaRally(
            int rallyLeaderId,
            List<int> participantIds,
            Dictionary<int, Dictionary<string, Dictionary<string, int>>> participantTroops,
            Dictionary<string, decimal> rallyLeaderBonuses,
            List<Dictionary<string, decimal>>? heroBonus,
            int rallyCapacity,
            int targetId,
            Dictionary<string, Dictionary<string, int>> defenderTroops,
            Dictionary<string, decimal> defenderBonuses)
        {
            try
            {
                // Calculate total troop count
                var totalTroops = CombineAllParticipantTroops(participantTroops);
                var totalTroopCount = totalTroops.Values.SelectMany(tier => tier.Values).Sum();

                if (totalTroopCount > rallyCapacity)
                {
                    throw new InvalidOperationException($"Mega rally exceeds capacity: {totalTroopCount} > {rallyCapacity}");
                }

                // Apply hero bonuses to leader stats
                var enhancedLeaderBonuses = ApplyHeroBonusesToLeaderStats(rallyLeaderBonuses, heroBonus);

                // Calculate battle using leader's enhanced stats for all troops
                var battleStats = CalculateBattleStats(
                    rallyLeaderId,
                    targetId,
                    totalTroops,
                    defenderTroops,
                    enhancedLeaderBonuses,
                    defenderBonuses,
                    false,
                    true, // isMegaRally
                    enhancedLeaderBonuses);

                var combatResult = ExecuteStatisticalCombat(
                    battleStats,
                    totalTroops,
                    defenderTroops,
                    true, // Combined dragon effects
                    ExtractAllDragonSkills(heroBonus));

                return new Dictionary<string, object>
                {
                    ["RallyType"] = "Mega",
                    ["RallyLeaderId"] = rallyLeaderId,
                    ["ParticipantCount"] = participantIds.Count,
                    ["TotalTroopCount"] = totalTroopCount,
                    ["RallyCapacity"] = rallyCapacity,
                    ["EnhancedLeaderStats"] = enhancedLeaderBonuses,
                    ["BattleStats"] = battleStats,
                    ["CombatResult"] = combatResult,
                    ["HeroBonusesApplied"] = heroBonus?.Count ?? 0,
                    ["RallyTime"] = DateTime.UtcNow
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to process mega rally led by {RallyLeaderId}", rallyLeaderId);
                throw;
            }
        }

        #endregion

        #region Private Helper Methods

        /// <summary>
        /// Calculates effective combat stats for a player's army
        /// </summary>
        private Dictionary<string, decimal> CalculateEffectiveStats(
            Dictionary<string, Dictionary<string, int>> troops,
            Dictionary<string, decimal> playerBonuses,
            CombatBalanceConfig balance)
        {
            var stats = new Dictionary<string, decimal>
            {
                ["TotalAttack"] = 0m,
                ["TotalDefense"] = 0m,
                ["TotalHealth"] = 0m
            };

            foreach (var troopType in troops.Keys)
            {
                if (!balance.BaseTroopStats.ContainsKey(troopType)) continue;

                var baseStats = balance.BaseTroopStats[troopType];

                foreach (var tierEntry in troops[troopType])
                {
                    if (!int.TryParse(tierEntry.Key.Replace("T", ""), out int tier)) continue;
                    if (!balance.TroopTierMultipliers.ContainsKey(tier)) continue;

                    var count = tierEntry.Value;
                    var tierMultiplier = balance.TroopTierMultipliers[tier];

                    // Apply bonuses from player (VIP, research, equipment, etc.)
                    var attackBonus = playerBonuses.GetValueOrDefault($"{troopType}Attack", 0m) + playerBonuses.GetValueOrDefault("TroopAttack", 0m);
                    var defenseBonus = playerBonuses.GetValueOrDefault($"{troopType}Defense", 0m) + playerBonuses.GetValueOrDefault("TroopDefense", 0m);
                    var healthBonus = playerBonuses.GetValueOrDefault($"{troopType}Health", 0m) + playerBonuses.GetValueOrDefault("TroopHealth", 0m);

                    var effectiveAttack = baseStats.BaseAttack * tierMultiplier * (1 + attackBonus / 100m) * count;
                    var effectiveDefense = baseStats.BaseDefense * tierMultiplier * (1 + defenseBonus / 100m) * count;
                    var effectiveHealth = baseStats.BaseHealth * tierMultiplier * (1 + healthBonus / 100m) * count;

                    stats["TotalAttack"] += effectiveAttack;
                    stats["TotalDefense"] += effectiveDefense;
                    stats["TotalHealth"] += effectiveHealth;
                }
            }

            return stats;
        }

        /// <summary>
        /// Applies field interception combat modifiers
        /// </summary>
        private void ApplyFieldInterceptionModifiers(
            Dictionary<string, decimal> attackerStats,
            Dictionary<string, decimal> defenderStats,
            CombatBalanceConfig balance)
        {
            // Defender advantages in field interception
            defenderStats["TotalDefense"] *= (1 + balance.FieldInterceptionDefenseBonus);
            defenderStats["TotalAttack"] *= (1 + balance.FieldInterceptionAttackBonus);

            // Attacker penalties (march fatigue, positioning disadvantage)
            attackerStats["TotalAttack"] *= (1 - balance.FieldInterceptionAttackerPenalty);
            attackerStats["TotalHealth"] *= (1 - balance.FieldInterceptionAttackerPenalty);
        }

        /// <summary>
        /// Calculates total power score from combat stats
        /// </summary>
        private decimal CalculateTotalPowerScore(Dictionary<string, decimal> stats, Dictionary<string, Dictionary<string, int>> troops)
        {
            // Weighted power calculation
            var attackWeight = 0.35m;
            var defenseWeight = 0.35m;
            var healthWeight = 0.30m;

            return (stats["TotalAttack"] * attackWeight) +
                   (stats["TotalDefense"] * defenseWeight) +
                   (stats["TotalHealth"] * healthWeight);
        }

        /// <summary>
        /// Calculates win probability based on power difference
        /// </summary>
        private decimal CalculateWinProbability(decimal attackerPower, decimal defenderPower)
        {
            if (attackerPower + defenderPower == 0) return 0.5m;

            var powerRatio = attackerPower / (attackerPower + defenderPower);

            // Apply sigmoid curve for more realistic probability distribution
            var adjustedRatio = (decimal)(1 / (1 + Math.Exp(-5 * ((double)powerRatio - 0.5))));

            return Math.Max(0.05m, Math.Min(0.95m, adjustedRatio));
        }

        /// <summary>
        /// Applies RNG variance to combat calculations
        /// </summary>
        private decimal ApplyRngVariance(decimal variancePercentage)
        {
            var variance = (decimal)(_random.NextDouble() - 0.5) * 2 * variancePercentage;
            return variance;
        }

        /// <summary>
        /// Checks for critical combat events
        /// </summary>
        private Dictionary<string, object>? CheckForCriticalEvents(decimal criticalChance)
        {
            if (_random.NextDecimal() < criticalChance)
            {
                var events = new[] { "Tactical Breakthrough", "Perfect Formation", "Surprise Flanking", "Weather Advantage" };
                var selectedEvent = events[_random.Next(events.Length)];

                return new Dictionary<string, object>
                {
                    ["EventType"] = selectedEvent,
                    ["Bonus"] = _random.Next(5, 15), // 5-15% bonus
                    ["Description"] = $"A {selectedEvent} provided tactical advantage in battle"
                };
            }
            return null;
        }

        /// <summary>
        /// Checks for dragon skill activation
        /// </summary>
        private Dictionary<string, object>? CheckForDragonSkillActivation(decimal activationChance, List<string>? dragonSkills)
        {
            if (dragonSkills == null || dragonSkills.Count == 0) return null;

            if (_random.NextDecimal() < activationChance)
            {
                var skill = dragonSkills[_random.Next(dragonSkills.Count)];
                var damage = _random.Next(1000, 10000); // Variable dragon skill damage

                return new Dictionary<string, object>
                {
                    ["SkillName"] = skill,
                    ["Damage"] = damage,
                    ["Description"] = $"{skill} activated for {damage:N0} additional damage"
                };
            }
            return null;
        }

        /// <summary>
        /// Calculates casualties with tier priority (higher tiers die last)
        /// </summary>
        private Dictionary<string, object> CalculateBattleCasualtiesWithTierPriority(
            Dictionary<string, Dictionary<string, int>> attackerTroops,
            Dictionary<string, Dictionary<string, int>> defenderTroops,
            bool attackerWins,
            decimal winProbability,
            Dictionary<string, object>? criticalEvent,
            Dictionary<string, object>? dragonSkill,
            CombatBalanceConfig balance)
        {
            // Calculate base casualty rates
            var attackerCasualtyRate = attackerWins ?
                0.15m + (0.25m * (1 - winProbability)) : // Winner loses 15-40%
                0.60m + (0.30m * (1 - winProbability));   // Loser loses 60-90%

            var defenderCasualtyRate = attackerWins ?
                0.70m + (0.25m * winProbability) :        // Loser loses 70-95%
                0.10m + (0.20m * winProbability);         // Winner loses 10-30%

            // Apply modifiers
            if (criticalEvent != null)
            {
                var bonus = (int)criticalEvent["Bonus"];
                if (attackerWins)
                    defenderCasualtyRate += bonus / 100m;
                else
                    attackerCasualtyRate += bonus / 100m;
            }

            if (dragonSkill != null)
            {
                // Dragon skills increase enemy casualties
                if (attackerWins)
                    defenderCasualtyRate += 0.05m;
                else
                    attackerCasualtyRate += 0.05m;
            }

            // Calculate casualties with tier priority
            var attackerCasualties = CalculateTierPriorityCasualties(attackerTroops, attackerCasualtyRate);
            var defenderCasualties = CalculateTierPriorityCasualties(defenderTroops, defenderCasualtyRate);

            return new Dictionary<string, object>
            {
                ["AttackerCasualties"] = attackerCasualties,
                ["DefenderCasualties"] = defenderCasualties,
                ["AttackerCasualtyRate"] = attackerCasualtyRate,
                ["DefenderCasualtyRate"] = defenderCasualtyRate
            };
        }

        /// <summary>
        /// Calculates casualties with tier priority - lower tiers die first
        /// </summary>
        private Dictionary<string, Dictionary<string, int>> CalculateTierPriorityCasualties(
            Dictionary<string, Dictionary<string, int>> troops,
            decimal casualtyRate)
        {
            var casualties = new Dictionary<string, Dictionary<string, int>>();

            foreach (var troopType in troops.Keys)
            {
                casualties[troopType] = new Dictionary<string, int>();
                var totalTroops = troops[troopType].Values.Sum();
                var totalCasualties = (int)(totalTroops * casualtyRate);

                var remainingCasualties = totalCasualties;

                // Sort tiers from lowest to highest (T1, T2, T3, etc.)
                var sortedTiers = troops[troopType].Keys
                    .OrderBy(tier => int.Parse(tier.Replace("T", "")))
                    .ToList();

                foreach (var tier in sortedTiers)
                {
                    if (remainingCasualties <= 0) break;

                    var availableTroops = troops[troopType][tier];
                    var tierCasualties = Math.Min(remainingCasualties, availableTroops);

                    casualties[troopType][tier] = tierCasualties;
                    remainingCasualties -= tierCasualties;
                }
            }

            return casualties;
        }

        /// <summary>
        /// Processes hospital cascade system: Personal → Alliance → Sanctum → Death
        /// </summary>
        private Dictionary<string, object> ProcessHospitalCascade(
            Dictionary<string, Dictionary<string, int>> casualties,
            int personalHospitalCapacity,
            int allianceHospitalCapacity,
            bool hasVip10,
            bool hasSubscription,
            CombatBalanceConfig balance)
        {
            var totalCasualties = casualties.Values.SelectMany(tier => tier.Values).Sum();

            // Calculate wounded vs killed (configurable split)
            var totalWounded = (int)(totalCasualties * balance.BaseWoundedPercentage);
            var immediatelyKilled = totalCasualties - totalWounded;

            // Calculate Sanctum capacity and bonus
            var sanctumPercentage = balance.SanctumBasePercentage;
            if (hasVip10) sanctumPercentage += balance.SanctumVipBonus;
            if (hasSubscription) sanctumPercentage += balance.SanctumSubscriptionBonus;

            var sanctumCapacity = (int)(personalHospitalCapacity * balance.SanctumCapacityMultiplier);
            if (hasVip10) sanctumCapacity += personalHospitalCapacity;
            if (hasSubscription) sanctumCapacity += personalHospitalCapacity;

            // Process cascade
            var remainingWounded = totalWounded;
            var personalHospital = Math.Min(remainingWounded, personalHospitalCapacity);
            remainingWounded -= personalHospital;

            var allianceHospital = Math.Min(remainingWounded, allianceHospitalCapacity);
            remainingWounded -= allianceHospital;

            // Calculate Sanctum allocation (percentage of remaining wounded)
            var sanctumWounded = (int)(remainingWounded * sanctumPercentage);
            sanctumWounded = Math.Min(sanctumWounded, sanctumCapacity);
            remainingWounded -= sanctumWounded;

            // Remaining wounded die
            var additionalKilled = remainingWounded;
            var totalKilled = immediatelyKilled + additionalKilled;

            return new Dictionary<string, object>
            {
                ["TotalCasualties"] = totalCasualties,
                ["TotalWounded"] = totalWounded,
                ["TotalKilled"] = totalKilled,
                ["PersonalHospital"] = personalHospital,
                ["AllianceHospital"] = allianceHospital,
                ["SanctumWounded"] = sanctumWounded,
                ["SanctumCapacity"] = sanctumCapacity,
                ["SanctumPercentage"] = sanctumPercentage,
                ["OverflowKilled"] = additionalKilled,
                ["ImmediatelyKilled"] = immediatelyKilled
            };
        }

        /// <summary>
        /// Combines troops from all rally participants
        /// </summary>
        private Dictionary<string, Dictionary<string, int>> CombineAllParticipantTroops(
            Dictionary<int, Dictionary<string, Dictionary<string, int>>> participantTroops)
        {
            var combined = new Dictionary<string, Dictionary<string, int>>();

            foreach (var participant in participantTroops.Values)
            {
                foreach (var troopType in participant.Keys)
                {
                    if (!combined.ContainsKey(troopType))
                        combined[troopType] = new Dictionary<string, int>();

                    foreach (var tier in participant[troopType].Keys)
                    {
                        if (!combined[troopType].ContainsKey(tier))
                            combined[troopType][tier] = 0;

                        combined[troopType][tier] += participant[troopType][tier];
                    }
                }
            }

            return combined;
        }

        /// <summary>
        /// Applies hero bonuses to rally leader stats (stacking for mega rallies)
        /// </summary>
        private Dictionary<string, decimal> ApplyHeroBonusesToLeaderStats(
            Dictionary<string, decimal> leaderBonuses,
            List<Dictionary<string, decimal>>? heroBonuses)
        {
            if (heroBonuses == null) return new Dictionary<string, decimal>(leaderBonuses);

            var enhanced = new Dictionary<string, decimal>(leaderBonuses);

            foreach (var heroBonus in heroBonuses)
            {
                foreach (var bonus in heroBonus)
                {
                    if (!enhanced.ContainsKey(bonus.Key))
                        enhanced[bonus.Key] = 0m;

                    enhanced[bonus.Key] += bonus.Value; // Additive stacking
                }
            }

            return enhanced;
        }

        /// <summary>
        /// Extracts all dragon skills from hero bonuses
        /// </summary>
        private List<string> ExtractAllDragonSkills(List<Dictionary<string, decimal>>? heroBonuses)
        {
            var skills = new List<string>();
            if (heroBonuses == null) return skills;

            // Look for dragon skill indicators in hero bonuses
            foreach (var heroBonus in heroBonuses)
            {
                if (heroBonus.ContainsKey("DragonSkill"))
                {
                    // Add common dragon skills - this should be configurable
                    skills.AddRange(new[] { "Rain of Fire", "Breath of Fire", "Ice Storm", "Lightning Strike" });
                }
            }

            return skills.Distinct().ToList();
        }

        /// <summary>
        /// Combines results from standard rally participants
        /// </summary>
        private Dictionary<string, object> CombineRallyResults(List<Dictionary<string, object>> individualResults)
        {
            var combinedOutcome = new Dictionary<string, object>
            {
                ["TotalWins"] = individualResults.Count(r => (bool)((Dictionary<string, object>)r["CombatResult"])["AttackerWins"]),
                ["TotalLosses"] = individualResults.Count(r => !(bool)((Dictionary<string, object>)r["CombatResult"])["AttackerWins"]),
                ["CombinedSuccess"] = individualResults.Count(r => (bool)((Dictionary<string, object>)r["CombatResult"])["AttackerWins"]) > individualResults.Count / 2
            };

            return combinedOutcome;
        }

        #endregion
    }

    #region Configuration Classes

    /// <summary>
    /// Combat balance configuration settings
    /// </summary>
    public class CombatBalanceConfig
    {
        public decimal RngVariancePercentage { get; set; }
        public decimal CriticalEventChance { get; set; }
        public decimal DragonSkillActivationChance { get; set; }

        public decimal BaseWoundedPercentage { get; set; }
        public decimal BaseKilledPercentage { get; set; }
        public decimal SanctumBasePercentage { get; set; }
        public decimal SanctumVipBonus { get; set; }
        public decimal SanctumSubscriptionBonus { get; set; }
        public decimal SanctumCapacityMultiplier { get; set; }

        public Dictionary<int, decimal> TroopTierMultipliers { get; set; } = new();
        public Dictionary<string, TroopBaseStats> BaseTroopStats { get; set; } = new();

        public decimal FieldInterceptionDefenseBonus { get; set; }
        public decimal FieldInterceptionAttackBonus { get; set; }
        public decimal FieldInterceptionAttackerPenalty { get; set; }
    }

    /// <summary>
    /// Base stats for troop types
    /// </summary>
    public class TroopBaseStats
    {
        public decimal BaseAttack { get; set; }
        public decimal BaseDefense { get; set; }
        public decimal BaseHealth { get; set; }
    }

    #endregion

    #region Extension Methods

    public static class RandomExtensions
    {
        public static decimal NextDecimal(this Random random)
        {
            return (decimal)random.NextDouble();
        }
    }

    #endregion
}