/*
 * File: D:\shadowed-realms-mobile\ShadowedRealmsMobile\src\server\ShadowedRealms.API\Services\MarchSpeedEngine.cs
 * Created: 2025-10-30
 * Last Modified: 2025-10-30
 * Description: Complete march speed and movement limitation system with strategic timing, diminishing returns, and anti-pay-to-win balance
 * Last Edit Notes: Fixed compilation errors - corrected Player property references (Id instead of PlayerId) and added missing MIN_MARCH_TIME_MINUTES constant
 */

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using ShadowedRealms.Core.Models;
using ShadowedRealms.Core.Models.Player;

namespace ShadowedRealms.API.Services
{
    /// <summary>
    /// Complete march speed calculation engine with strategic limitations and anti-pay-to-win balance
    /// </summary>
    public class MarchSpeedEngine
    {
        private readonly IConfiguration _configuration;
        private readonly ILogger<MarchSpeedEngine> _logger;
        private readonly Random _random;

        // March constants from configuration
        private const double MIN_MARCH_TIME_SECONDS = 10.0; // Minimum 10 seconds for instant local attacks
        private const double MIN_MARCH_TIME_MINUTES = MIN_MARCH_TIME_SECONDS / 60.0; // Minimum march time in minutes
        private const double BASE_MARCH_SPEED = 50.0; // Base speed units per minute
        private const double DIMINISHING_RETURNS_THRESHOLD = 10000; // Troop count where diminishing returns begin
        private const double MAX_VIP_SPEED_BONUS = 25.0; // Maximum VIP speed bonus percentage
        private const double FOREST_SPEED_PENALTY = 0.5; // 50% speed reduction in forest barriers

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

        #region March Time Calculation

        /// <summary>
        /// Calculate complete march time with all modifiers and limitations
        /// </summary>
        public Dictionary<string, object> CalculateMarchTime(
            Player marcher,
            (int X, int Y) startCoordinates,
            (int X, int Y) targetCoordinates,
            Dictionary<string, Dictionary<string, int>> troopComposition,
            string marchType = "StandardMarch",
            Dictionary<string, object>? additionalModifiers = null)
        {
            try
            {
                var result = new Dictionary<string, object>();
                var distance = CalculateDistance(startCoordinates, targetCoordinates);
                var totalTroops = troopComposition.Values.SelectMany(t => t.Values).Sum();

                // Base march time calculation
                var baseMarchTime = CalculateBaseMarchTime(distance, totalTroops);
                result["BaseMarchTime"] = TimeSpan.FromMinutes(baseMarchTime);

                // Troop composition speed modifier
                var troopSpeedModifier = CalculateTroopSpeedModifier(troopComposition);
                result["TroopSpeedModifier"] = troopSpeedModifier;

                // Army size diminishing returns
                var armySizePenalty = CalculateArmySizePenalty(totalTroops);
                result["ArmySizePenalty"] = armySizePenalty;

                // March type modifier
                var marchTypeModifier = GetMarchTypeModifier(marchType);
                result["MarchTypeModifier"] = marchTypeModifier;

                // VIP speed bonuses with diminishing returns
                var vipSpeedBonus = CalculateVipSpeedBonus(marcher.VipLevel);
                result["VipSpeedBonus"] = vipSpeedBonus;

                // Alliance research bonuses
                var allianceSpeedBonus = GetAllianceResearchBonus(marcher.AllianceId);
                result["AllianceSpeedBonus"] = allianceSpeedBonus;

                // Dragon speed bonuses
                var dragonSpeedBonus = CalculateDragonSpeedBonus(additionalModifiers);
                result["DragonSpeedBonus"] = dragonSpeedBonus;

                // Terrain penalties (forest barriers, etc.)
                var terrainPenalty = CalculateTerrainPenalty(startCoordinates, targetCoordinates);
                result["TerrainPenalty"] = terrainPenalty;

                // Calculate final march time
                var finalMarchTime = baseMarchTime * troopSpeedModifier * armySizePenalty * marchTypeModifier * terrainPenalty;

                // Apply bonuses (multiplicative)
                finalMarchTime /= (1.0 + vipSpeedBonus + allianceSpeedBonus + dragonSpeedBonus);

                // Enforce minimum march time (10 seconds for instant local attacks)
                finalMarchTime = Math.Max(MIN_MARCH_TIME_SECONDS / 60.0, finalMarchTime);

                result["FinalMarchTime"] = TimeSpan.FromMinutes(finalMarchTime);
                result["Distance"] = distance;
                result["TotalTroops"] = totalTroops;

                // Calculate grace period for defenders
                var gracePeriod = CalculateGracePeriod(marcher, finalMarchTime);
                result["DefenderGracePeriod"] = gracePeriod;

                // Arrival time
                result["EstimatedArrivalTime"] = DateTime.UtcNow.AddMinutes(finalMarchTime);

                _logger.LogInformation($"March calculated: {totalTroops} troops, {distance:F1} distance, {finalMarchTime:F1} minutes");

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error calculating march time for player {PlayerId}", marcher.Id);
                throw;
            }
        }

        /// <summary>
        /// Validate march restrictions and limitations
        /// </summary>
        public (bool IsValid, List<string> Restrictions) ValidateMarch(
            Player marcher,
            (int X, int Y) targetCoordinates,
            Dictionary<string, Dictionary<string, int>> troopComposition,
            string marchType)
        {
            var restrictions = new List<string>();

            // Check minimum march time enforcement
            var marchTimeResult = CalculateMarchTime(
                marcher,
                (marcher.CoordinateX, marcher.CoordinateY),
                targetCoordinates,
                troopComposition,
                marchType);

            var finalMarchTime = (TimeSpan)marchTimeResult["FinalMarchTime"];

            if (finalMarchTime.TotalSeconds < MIN_MARCH_TIME_SECONDS)
            {
                restrictions.Add($"March time cannot be less than {MIN_MARCH_TIME_SECONDS} seconds (Technical minimum)");
            }

            // Check army size limitations
            var totalTroops = troopComposition.Values.SelectMany(t => t.Values).Sum();
            var maxArmySize = GetMaxArmySize(marcher);

            if (totalTroops > maxArmySize)
            {
                restrictions.Add($"Army size {totalTroops:N0} exceeds maximum allowed {maxArmySize:N0}");
            }

            // Check march type restrictions
            var marchTypeRestrictions = ValidateMarchType(marcher, marchType, totalTroops);
            restrictions.AddRange(marchTypeRestrictions);

            // Check teleportation limitations
            var teleportRestrictions = ValidateTeleportation(marcher, targetCoordinates);
            restrictions.AddRange(teleportRestrictions);

            return (restrictions.Count == 0, restrictions);
        }

        #endregion

        #region Speed Calculation Helpers

        /// <summary>
        /// Calculate base march time from distance and army size
        /// </summary>
        private double CalculateBaseMarchTime(double distance, int totalTroops)
        {
            // Base time calculation: distance / speed, with army size factor
            var baseSpeed = BASE_MARCH_SPEED;

            // Larger armies move slightly slower (logistics complexity)
            var armySpeedReduction = Math.Min(0.3, totalTroops / 100000.0 * 0.1); // Max 30% reduction
            var effectiveSpeed = baseSpeed * (1.0 - armySpeedReduction);

            // Calculate march time in minutes, then convert to seconds for final check
            var marchTimeMinutes = distance / effectiveSpeed;
            var marchTimeSeconds = marchTimeMinutes * 60;

            // Minimum 10 seconds (allows for instant local attacks)
            return Math.Max(MIN_MARCH_TIME_SECONDS / 60.0, marchTimeMinutes);
        }

        /// <summary>
        /// Calculate troop type speed modifier based on army composition
        /// </summary>
        private double CalculateTroopSpeedModifier(Dictionary<string, Dictionary<string, int>> troopComposition)
        {
            var totalTroops = troopComposition.Values.SelectMany(t => t.Values).Sum();
            if (totalTroops == 0) return 1.0;

            var weightedSpeed = 0.0;

            // Troop type speed multipliers
            var troopSpeeds = new Dictionary<string, double>
            {
                ["Infantry"] = 1.0,     // Base speed
                ["Cavalry"] = 1.3,      // 30% faster
                ["Bowmen"] = 1.1,       // 10% faster
                ["Siege"] = 0.7         // 30% slower (heavy equipment)
            };

            foreach (var troopType in troopComposition)
            {
                var troopCount = troopType.Value.Values.Sum();
                var speedMultiplier = troopSpeeds.GetValueOrDefault(troopType.Key, 1.0);
                weightedSpeed += (troopCount / (double)totalTroops) * speedMultiplier;
            }

            return weightedSpeed;
        }

        /// <summary>
        /// Calculate army size penalty with diminishing returns
        /// </summary>
        private double CalculateArmySizePenalty(int totalTroops)
        {
            if (totalTroops <= DIMINISHING_RETURNS_THRESHOLD) return 1.0;

            // Apply diminishing returns penalty for very large armies
            var excessTroops = totalTroops - DIMINISHING_RETURNS_THRESHOLD;
            var penaltyFactor = Math.Min(0.5, excessTroops / (DIMINISHING_RETURNS_THRESHOLD * 2.0)); // Max 50% penalty

            return 1.0 + penaltyFactor; // Higher value = slower march (penalty)
        }

        /// <summary>
        /// Get march type speed modifier
        /// </summary>
        private double GetMarchTypeModifier(string marchType)
        {
            return marchType switch
            {
                "LightningRaid" => 0.8,        // 20% faster
                "StandardMarch" => 1.0,        // Normal speed
                "CautiousAdvance" => 1.2,      // 20% slower but safer
                "CastleSiege" => 1.4,          // 40% slower (siege equipment)
                "MassiveAssault" => 1.6,       // 60% slower (coordination complexity)
                _ => 1.0
            };
        }

        /// <summary>
        /// Calculate VIP speed bonus with diminishing returns
        /// </summary>
        private double CalculateVipSpeedBonus(int vipLevel)
        {
            if (vipLevel <= 0) return 0.0;

            // Diminishing returns: each VIP level provides less bonus
            var baseBonus = Math.Min(vipLevel * 2.0, MAX_VIP_SPEED_BONUS); // 2% per level, max 25%
            var diminishingFactor = 1.0 - Math.Min(0.3, vipLevel / 50.0); // Reduces effectiveness at higher levels

            return (baseBonus / 100.0) * diminishingFactor;
        }

        /// <summary>
        /// Get alliance research speed bonus
        /// </summary>
        private double GetAllianceResearchBonus(int? allianceId)
        {
            if (!allianceId.HasValue) return 0.0;

            // Alliance research can provide up to 15% speed bonus
            // This would be loaded from database in real implementation
            return 0.10; // Placeholder: 10% alliance research bonus
        }

        /// <summary>
        /// Calculate dragon speed bonus
        /// </summary>
        private double CalculateDragonSpeedBonus(Dictionary<string, object>? additionalModifiers)
        {
            if (additionalModifiers == null) return 0.0;

            var dragonBonus = 0.0;

            if (additionalModifiers.ContainsKey("DragonSpeedSkill"))
            {
                var skillLevel = Convert.ToInt32(additionalModifiers["DragonSpeedSkill"]);
                dragonBonus = Math.Min(0.20, skillLevel * 0.02); // Max 20% from dragon skills
            }

            return dragonBonus;
        }

        /// <summary>
        /// Calculate terrain movement penalty
        /// </summary>
        private double CalculateTerrainPenalty(
            (int X, int Y) startCoordinates,
            (int X, int Y) targetCoordinates)
        {
            // Check if march passes through forest barriers
            var passesForest = CheckForestBarrierCrossing(startCoordinates, targetCoordinates);

            if (passesForest)
            {
                return 1.0 + FOREST_SPEED_PENALTY; // 50% slower through forest
            }

            // Other terrain types could be added here
            return 1.0; // No terrain penalty
        }

        #endregion

        #region March Restrictions and Grace Periods

        /// <summary>
        /// Calculate defender grace period
        /// </summary>
        private TimeSpan CalculateGracePeriod(Player marcher, double marchTimeMinutes)
        {
            // Grace period ensures defenders have time to react
            var baseMarchTime = Math.Max(MIN_MARCH_TIME_MINUTES, marchTimeMinutes);

            // Grace period is percentage of march time, minimum 2 seconds
            var gracePeriodMinutes = Math.Max(2.0 / 60.0, baseMarchTime * 0.2); // 20% of march time, min 2 seconds

            return TimeSpan.FromMinutes(gracePeriodMinutes);
        }

        /// <summary>
        /// Validate march type restrictions
        /// </summary>
        private List<string> ValidateMarchType(Player marcher, string marchType, int troopCount)
        {
            var restrictions = new List<string>();

            switch (marchType)
            {
                case "LightningRaid":
                    if (troopCount > 5000)
                        restrictions.Add("Lightning raids limited to 5,000 troops maximum");
                    break;

                case "MassiveAssault":
                    if (marcher.CastleLevel < 20)
                        restrictions.Add("Massive assaults require castle level 20+");
                    if (troopCount < 50000)
                        restrictions.Add("Massive assaults require minimum 50,000 troops");
                    break;

                case "CastleSiege":
                    if (marcher.CastleLevel < 15)
                        restrictions.Add("Castle sieges require castle level 15+");
                    break;
            }

            return restrictions;
        }

        /// <summary>
        /// Validate teleportation restrictions
        /// </summary>
        private List<string> ValidateTeleportation(Player marcher, (int X, int Y) targetCoordinates)
        {
            var restrictions = new List<string>();
            var distance = CalculateDistance((marcher.CoordinateX, marcher.CoordinateY), targetCoordinates);

            // Teleportation restrictions based on distance and proximity
            if (distance > 1000)
            {
                restrictions.Add("Cannot teleport more than 1,000 coordinate units");
            }

            // Check proximity to other players (anti-teleportation camping)
            if (IsNearEnemyPlayer(targetCoordinates, marcher.KingdomId))
            {
                restrictions.Add("Cannot teleport within 50 units of enemy players");
            }

            // VIP level teleportation limits
            var maxTeleportsPerDay = GetMaxTeleportsPerDay(marcher.VipLevel);
            // This would check database for today's teleportation count

            return restrictions;
        }

        #endregion

        #region Utility Methods

        /// <summary>
        /// Calculate distance between two coordinates
        /// </summary>
        private double CalculateDistance((int X, int Y) from, (int X, int Y) to)
        {
            var deltaX = to.X - from.X;
            var deltaY = to.Y - from.Y;
            return Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
        }

        /// <summary>
        /// Check if march route crosses forest barriers
        /// </summary>
        private bool CheckForestBarrierCrossing((int X, int Y) start, (int X, int Y) end)
        {
            // Simplified forest barrier detection
            // In real implementation, this would check against kingdom barrier coordinates
            var midPointX = (start.X + end.X) / 2;
            var midPointY = (start.Y + end.Y) / 2;

            // Forest barriers typically exist between kingdom boundaries
            return Math.Abs(midPointX % 1000) < 50 || Math.Abs(midPointY % 1000) < 50;
        }

        /// <summary>
        /// Get maximum army size for player
        /// </summary>
        private int GetMaxArmySize(Player marcher)
        {
            // Base army size + castle level bonuses + VIP bonuses
            var baseSize = 10000;
            var castleLevelBonus = marcher.CastleLevel * 1000;
            var vipBonus = marcher.VipLevel * 500;

            return baseSize + castleLevelBonus + vipBonus;
        }

        /// <summary>
        /// Check if coordinates are near enemy players
        /// </summary>
        private bool IsNearEnemyPlayer((int X, int Y) coordinates, int playerKingdomId)
        {
            // This would query the database for nearby enemy players
            // Placeholder implementation
            return false;
        }

        /// <summary>
        /// Get maximum teleportations per day based on VIP level
        /// </summary>
        private int GetMaxTeleportsPerDay(int vipLevel)
        {
            return vipLevel switch
            {
                0 => 1,           // Free players: 1 teleport per day
                >= 1 and <= 5 => 2,    // VIP 1-5: 2 teleports per day
                >= 6 and <= 10 => 3,   // VIP 6-10: 3 teleports per day
                >= 11 => 5,       // VIP 11+: 5 teleports per day
            };
        }

        #endregion

        #region Public API Methods

        /// <summary>
        /// Get estimated march time for UI display
        /// </summary>
        public TimeSpan GetEstimatedMarchTime(
            Player marcher,
            (int X, int Y) targetCoordinates,
            int estimatedTroopCount,
            string marchType = "StandardMarch")
        {
            // Quick estimation for UI without full troop composition
            var distance = CalculateDistance((marcher.CoordinateX, marcher.CoordinateY), targetCoordinates);
            var baseMarchTime = CalculateBaseMarchTime(distance, estimatedTroopCount);

            var marchTypeModifier = GetMarchTypeModifier(marchType);
            var vipSpeedBonus = CalculateVipSpeedBonus(marcher.VipLevel);

            var estimatedTime = baseMarchTime * marchTypeModifier / (1.0 + vipSpeedBonus);
            estimatedTime = Math.Max(MIN_MARCH_TIME_MINUTES, estimatedTime);

            return TimeSpan.FromMinutes(estimatedTime);
        }

        /// <summary>
        /// Check if march speed bonuses are being abused (anti-cheat)
        /// </summary>
        public bool DetectSpeedAbuse(Player marcher, List<TimeSpan> recentMarchTimes)
        {
            // Detect if player is consistently achieving impossible march times
            var averageMarchTime = recentMarchTimes.Average(t => t.TotalMinutes);

            if (averageMarchTime < MIN_MARCH_TIME_MINUTES * 0.9) // 10% tolerance
            {
                _logger.LogWarning($"Potential speed abuse detected for player {marcher.Id}: Average march time {averageMarchTime:F1} minutes");
                return true;
            }

            return false;
        }

        #endregion
    }
}