/*
 * File: D:\shadowed-realms-mobile\ShadowedRealmsMobile\src\server\ShadowedRealms.API\Controllers\Player\PlayerController.cs
 * Created: 2025-10-19
 * Last Modified: 2025-10-26
 * Description: Comprehensive REST API controller for player management operations.
 *              Exposes all PlayerService functionality through RESTful endpoints with
 *              proper authentication, validation, and error handling.
 * Last Edit Notes: Fixed compilation errors by correcting DTO property usage, method signatures,
 *                  and interface compatibility with existing IPlayerService implementation.
 */

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using ShadowedRealms.Core.Interfaces.Services;
using ShadowedRealms.Shared.DTOs.Player;
using ShadowedRealms.Shared.DTOs.Common;
using System.Security.Claims;

namespace ShadowedRealms.API.Controllers.Player
{
    /// <summary>
    /// REST API controller for comprehensive player management operations
    /// </summary>
    [ApiController]
    [Route("api/v1/players")]
    [Authorize] // JWT authentication required for all endpoints
    [Produces("application/json")]
    [ProducesResponseType(typeof(ErrorResponseDto), 400)]
    [ProducesResponseType(typeof(ErrorResponseDto), 401)]
    [ProducesResponseType(typeof(ErrorResponseDto), 403)]
    [ProducesResponseType(typeof(ErrorResponseDto), 500)]
    public class PlayerController : ControllerBase
    {
        private readonly IPlayerService _playerService;
        private readonly ILogger<PlayerController> _logger;

        public PlayerController(
            IPlayerService playerService,
            ILogger<PlayerController> logger)
        {
            _playerService = playerService ?? throw new ArgumentNullException(nameof(playerService));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        #region Player Information and Profile Management

        /// <summary>
        /// Retrieves current player profile with comprehensive statistics
        /// </summary>
        /// <returns>Complete player profile including castle, resources, VIP status, and alliance</returns>
        [HttpGet("profile")]
        [ProducesResponseType(typeof(PlayerProfileResponseDto), 200)]
        public async Task<IActionResult> GetPlayerProfile()
        {
            try
            {
                var (playerId, kingdomId) = GetAuthenticatedPlayer();
                var playerInfo = await _playerService.GetPlayerProfileAsync(playerId, kingdomId, includePrivateData: true);

                var response = new PlayerProfileResponseDto
                {
                    PlayerId = playerId,
                    PlayerName = (string)playerInfo.GetValueOrDefault("PlayerName", "Unknown"),
                    CastleLevel = (int)playerInfo.GetValueOrDefault("CastleLevel", 1),
                    Power = (decimal)playerInfo.GetValueOrDefault("Power", 0),
                    VipTier = (int)playerInfo.GetValueOrDefault("VipTier", 0),
                    KingdomId = kingdomId,
                    AllianceId = playerInfo.ContainsKey("AllianceId") ? (int?)playerInfo["AllianceId"] : null,
                    AllianceName = playerInfo.GetValueOrDefault("AllianceName", null) as string,
                    Position = playerInfo.ContainsKey("Coordinates")
                        ? ((int X, int Y))playerInfo["Coordinates"]
                        : (0, 0),
                    Resources = playerInfo.ContainsKey("Resources")
                        ? (Dictionary<string, decimal>)playerInfo["Resources"]
                        : new Dictionary<string, decimal>(),
                    CombatStats = playerInfo.GetValueOrDefault("CombatStats", new Dictionary<string, object>()) as Dictionary<string, object>,
                    CreatedAt = (DateTime)playerInfo.GetValueOrDefault("CreatedAt", DateTime.UtcNow),
                    LastActiveAt = (DateTime)playerInfo.GetValueOrDefault("LastLogin", DateTime.UtcNow),
                    IsActive = true
                };

                _logger.LogInformation("Player profile retrieved successfully for Player {PlayerId} in Kingdom {KingdomId}",
                    playerId, kingdomId);

                return Ok(response);
            }
            catch (UnauthorizedAccessException ex)
            {
                _logger.LogWarning("Unauthorized access attempt: {Message}", ex.Message);
                return Forbid();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving player profile");
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to retrieve player profile",
                    Code = "PROFILE_ERROR"
                });
            }
        }

        /// <summary>
        /// Updates player profile settings and preferences
        /// </summary>
        /// <param name="request">Profile update settings</param>
        /// <returns>Updated profile information</returns>
        [HttpPut("profile")]
        [ProducesResponseType(typeof(PlayerProfileResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        public async Task<IActionResult> UpdatePlayerProfile([FromBody] UpdatePlayerProfileRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid profile update data",
                        Code = "INVALID_INPUT",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                // Build action details dictionary from request
                var actionDetails = new Dictionary<string, object>
                {
                    ["DisplayName"] = request.DisplayName ?? string.Empty,
                    ["AvatarId"] = request.AvatarId ?? string.Empty,
                    ["Description"] = request.Description ?? string.Empty,
                    ["LanguagePreference"] = request.LanguagePreference ?? string.Empty,
                    ["NotificationSettings"] = request.NotificationSettings,
                    ["PrivacySettings"] = request.PrivacySettings
                };

                // Validate profile update settings
                var (isValid, warnings, riskFactors) = await _playerService.ValidatePlayerActionAsync(
                    playerId, kingdomId, "profile_update", actionDetails);

                if (!isValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Profile update validation failed",
                        Code = "VALIDATION_FAILED",
                        Details = new Dictionary<string, object> { ["Warnings"] = warnings, ["RiskFactors"] = riskFactors }
                    });
                }

                // Get updated profile after validation
                var updatedProfile = await _playerService.GetPlayerProfileAsync(playerId, kingdomId, includePrivateData: true);

                var response = new PlayerProfileResponseDto
                {
                    PlayerId = playerId,
                    PlayerName = (string)updatedProfile.GetValueOrDefault("PlayerName", "Unknown"),
                    CastleLevel = (int)updatedProfile.GetValueOrDefault("CastleLevel", 1),
                    Power = (decimal)updatedProfile.GetValueOrDefault("Power", 0),
                    VipTier = (int)updatedProfile.GetValueOrDefault("VipTier", 0),
                    KingdomId = kingdomId,
                    AllianceId = updatedProfile.ContainsKey("AllianceId") ? (int?)updatedProfile["AllianceId"] : null,
                    AllianceName = updatedProfile.GetValueOrDefault("AllianceName", null) as string,
                    Position = updatedProfile.ContainsKey("Coordinates")
                        ? ((int X, int Y))updatedProfile["Coordinates"]
                        : (0, 0),
                    Resources = updatedProfile.ContainsKey("Resources")
                        ? (Dictionary<string, decimal>)updatedProfile["Resources"]
                        : new Dictionary<string, decimal>(),
                    CombatStats = updatedProfile.GetValueOrDefault("CombatStats", new Dictionary<string, object>()) as Dictionary<string, object>,
                    CreatedAt = (DateTime)updatedProfile.GetValueOrDefault("CreatedAt", DateTime.UtcNow),
                    LastActiveAt = (DateTime)updatedProfile.GetValueOrDefault("LastLogin", DateTime.UtcNow),
                    IsActive = true
                };

                _logger.LogInformation("Player profile updated successfully for Player {PlayerId}", playerId);
                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating player profile");
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to update player profile",
                    Code = "UPDATE_ERROR"
                });
            }
        }

        /// <summary>
        /// Retrieves current player rankings and leaderboard positions
        /// </summary>
        /// <param name="category">Ranking category (power, castle_level, kills, etc.)</param>
        /// <returns>Player rankings and position information</returns>
        [HttpGet("rankings")]
        [ProducesResponseType(typeof(PlayerRankingsResponseDto), 200)]
        public async Task<IActionResult> GetPlayerRankings([FromQuery] string category = "power")
        {
            try
            {
                var (playerId, kingdomId) = GetAuthenticatedPlayer();
                var rankings = await _playerService.GetPlayerRankingsAsync(playerId, kingdomId);

                var response = new PlayerRankingsResponseDto
                {
                    PlayerId = playerId,
                    OverallRank = (int)rankings.GetValueOrDefault("PowerRank", 0),
                    KingdomRank = (int)rankings.GetValueOrDefault("PowerRank", 0),
                    AllianceRank = rankings.ContainsKey("AllianceRank") ? (int?)rankings["AllianceRank"] : null,
                    CategoryRankings = new Dictionary<string, int>
                    {
                        ["Power"] = (int)rankings.GetValueOrDefault("PowerRank", 0),
                        ["Level"] = (int)rankings.GetValueOrDefault("LevelRank", 0),
                        ["Kills"] = (int)rankings.GetValueOrDefault("KillRank", 0)
                    },
                    PowerScore = 0, // Would be calculated from player data
                    LeaderboardContext = rankings,
                    CalculationTime = DateTime.UtcNow
                };

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving player rankings for category {Category}", category);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to retrieve rankings",
                    Code = "RANKINGS_ERROR"
                });
            }
        }

        #endregion

        #region Castle Management and Upgrades

        /// <summary>
        /// Retrieves current castle information including level, upgrades in progress, and requirements
        /// </summary>
        /// <returns>Complete castle status and upgrade information</returns>
        [HttpGet("castle")]
        [ProducesResponseType(typeof(CastleInfoResponseDto), 200)]
        public async Task<IActionResult> GetCastleInfo()
        {
            try
            {
                var (playerId, kingdomId) = GetAuthenticatedPlayer();
                var playerProfile = await _playerService.GetPlayerProfileAsync(playerId, kingdomId, includePrivateData: true);

                var response = new CastleInfoResponseDto
                {
                    PlayerId = playerId,
                    CastleLevel = (int)playerProfile.GetValueOrDefault("CastleLevel", 1),
                    Location = playerProfile.ContainsKey("Coordinates")
                        ? GetLocationDictionary((ValueTuple<int, int>)playerProfile["Coordinates"])
                        : new Dictionary<string, decimal> { ["X"] = 0, ["Y"] = 0 },
                    DefenseStatus = new Dictionary<string, object>
                    {
                        ["WallLevel"] = playerProfile.GetValueOrDefault("CastleLevel", 1),
                        ["DefenseRating"] = "Standard"
                    },
                    ProductionBuildings = new Dictionary<string, object>
                    {
                        ["Farms"] = 1,
                        ["Sawmills"] = 1,
                        ["Quarries"] = 1,
                        ["IronMines"] = 1
                    },
                    MilitaryBuildings = new Dictionary<string, object>
                    {
                        ["Barracks"] = 1,
                        ["Stables"] = 1,
                        ["Academy"] = 1
                    },
                    StationedTroops = new Dictionary<string, long>
                    {
                        ["Infantry"] = 100,
                        ["Archers"] = 50,
                        ["Cavalry"] = 25
                    },
                    UpgradeOptions = new List<Dictionary<string, object>>
                    {
                        new() { ["Type"] = "Castle", ["NextLevel"] = (int)playerProfile.GetValueOrDefault("CastleLevel", 1) + 1 }
                    },
                    LastUpdated = DateTime.UtcNow
                };

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving castle information for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to retrieve castle information",
                    Code = "CASTLE_INFO_ERROR"
                });
            }
        }

        /// <summary>
        /// Initiates castle upgrade process with resource validation and VIP bonuses
        /// </summary>
        /// <param name="request">Castle upgrade parameters</param>
        /// <returns>Upgrade result with new castle level and benefits granted</returns>
        [HttpPost("castle/upgrade")]
        [ProducesResponseType(typeof(CastleUpgradeResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        [ProducesResponseType(typeof(ErrorResponseDto), 409)] // Conflict - upgrade already in progress
        public async Task<IActionResult> UpgradeCastle([FromBody] CastleUpgradeRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid castle upgrade request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var (success, newCastleLevel, benefitsGranted) = await _playerService.UpgradeCastleAsync(
                    playerId, kingdomId, useSpeedups: request.UseVipBonuses);

                if (!success)
                {
                    return Conflict(new ErrorResponseDto
                    {
                        Message = "Castle upgrade failed - insufficient resources or upgrade already in progress",
                        Code = "UPGRADE_FAILED"
                    });
                }

                var response = new CastleUpgradeResponseDto
                {
                    PlayerId = playerId,
                    Success = success,
                    NewCastleLevel = newCastleLevel,
                    BenefitsGranted = benefitsGranted,
                    UpgradeTime = DateTime.UtcNow,
                    ResourcesConsumed = request.ResourceAllocation
                };

                _logger.LogInformation("Castle upgraded successfully for Player {PlayerId} to level {NewLevel}",
                    playerId, newCastleLevel);

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error upgrading castle for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to upgrade castle",
                    Code = "UPGRADE_ERROR"
                });
            }
        }

        #endregion

        #region VIP Management and Progression

        /// <summary>
        /// Retrieves current VIP status including tier, benefits, and progression
        /// </summary>
        /// <returns>Complete VIP information and secret tier status</returns>
        [HttpGet("vip")]
        [ProducesResponseType(typeof(VipStatusResponseDto), 200)]
        public async Task<IActionResult> GetVipStatus()
        {
            try
            {
                var (playerId, kingdomId) = GetAuthenticatedPlayer();
                var playerProfile = await _playerService.GetPlayerProfileAsync(playerId, kingdomId, includePrivateData: true);
                var vipTier = (int)playerProfile.GetValueOrDefault("VipTier", 0);
                var vipBenefits = await _playerService.GrantVipBenefitsAsync(playerId, kingdomId, vipTier);

                var response = new VipStatusResponseDto
                {
                    PlayerId = playerId,
                    VipStatus = new Dictionary<string, object>
                    {
                        ["VipTier"] = vipTier,
                        ["Benefits"] = vipBenefits,
                        ["IsSecretTier"] = vipTier >= 16
                    },
                    LastUpdated = DateTime.UtcNow
                };

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving VIP status for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to retrieve VIP status",
                    Code = "VIP_STATUS_ERROR"
                });
            }
        }

        /// <summary>
        /// Processes VIP advancement based on purchases and milestones
        /// </summary>
        /// <param name="request">VIP advancement parameters</param>
        /// <returns>VIP advancement result with new tier and benefits</returns>
        [HttpPost("vip/advance")]
        [ProducesResponseType(typeof(VipAdvancementResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        public async Task<IActionResult> AdvanceVip([FromBody] VipAdvancementRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid VIP advancement request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                // Use MaxSpendAmount as the purchase amount for advancement
                var (tierChanged, newVipTier, isSecretTier, newBenefits, chargebackRisk) =
                    await _playerService.ProcessVipAdvancementAsync(playerId, kingdomId, request.MaxSpendAmount);

                if (!tierChanged)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "VIP advancement failed - invalid purchase or tier requirements not met",
                        Code = "ADVANCEMENT_FAILED"
                    });
                }

                var response = new VipAdvancementResponseDto
                {
                    PlayerId = playerId,
                    PreviousVipLevel = Math.Max(1, newVipTier - 1),
                    NewVipLevel = newVipTier,
                    NewBenefits = new List<Dictionary<string, object>> { newBenefits },
                    VipPointsChanged = 100, // Placeholder
                    CurrentVipPoints = 1000, // Placeholder
                    PointsToNextLevel = newVipTier < 20 ? 200 : null,
                    Success = tierChanged,
                    AdvancementTime = DateTime.UtcNow,
                    VipProgressionData = new Dictionary<string, object>
                    {
                        ["IsSecretTier"] = isSecretTier,
                        ["ChargebackRisk"] = chargebackRisk
                    }
                };

                _logger.LogInformation("VIP advancement processed for Player {PlayerId} to tier {NewTier}",
                    playerId, newVipTier);

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing VIP advancement for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to process VIP advancement",
                    Code = "VIP_ADVANCEMENT_ERROR"
                });
            }
        }

        #endregion

        #region Teleportation and Movement

        /// <summary>
        /// Executes player teleportation with distance calculations and cost validation
        /// </summary>
        /// <param name="request">Teleportation target coordinates and parameters</param>
        /// <returns>Teleportation result with new position and costs</returns>
        [HttpPost("teleport")]
        [ProducesResponseType(typeof(TeleportationResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        [ProducesResponseType(typeof(ErrorResponseDto), 409)] // Conflict - cooldown or proximity block
        public async Task<IActionResult> ExecuteTeleportation([FromBody] TeleportationRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid teleportation request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var (success, newX, newY, costsApplied, nextTeleportAvailable) =
                    await _playerService.ExecuteTeleportationAsync(
                        playerId, kingdomId, request.Destination.X, request.Destination.Y, "paid");

                if (!success)
                {
                    var errorMessage = "Teleportation failed - insufficient resources or blocked";

                    return Conflict(new ErrorResponseDto
                    {
                        Message = errorMessage,
                        Code = "TELEPORTATION_FAILED",
                        Details = new Dictionary<string, object>
                        {
                            ["nextTeleportAvailable"] = nextTeleportAvailable
                        }
                    });
                }

                var response = new TeleportationResponseDto
                {
                    Success = success,
                    NewPosition = (newX, newY),
                    CostBreakdown = costsApplied.ToDictionary(kvp => kvp.Key, kvp => Convert.ToDecimal(kvp.Value)),
                    RestrictionsApplied = new List<string>(),
                    TeleportationTime = DateTime.UtcNow
                };

                _logger.LogInformation("Teleportation executed successfully for Player {PlayerId} to ({X}, {Y})",
                    playerId, request.Destination.X, request.Destination.Y);

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error executing teleportation for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to execute teleportation",
                    Code = "TELEPORTATION_ERROR"
                });
            }
        }

        #endregion

        #region Resource Management

        /// <summary>
        /// Retrieves current player resources including production rates and capacity
        /// </summary>
        /// <returns>Complete resource status and production information</returns>
        [HttpGet("resources")]
        [ProducesResponseType(typeof(ResourceStatusResponseDto), 200)]
        public async Task<IActionResult> GetResourceStatus()
        {
            try
            {
                var (playerId, kingdomId) = GetAuthenticatedPlayer();
                var productionData = await _playerService.CalculateResourceProductionAsync(playerId, kingdomId);
                var playerProfile = await _playerService.GetPlayerProfileAsync(playerId, kingdomId, includePrivateData: true);

                var response = new ResourceStatusResponseDto
                {
                    PlayerId = playerId,
                    CurrentResources = playerProfile.ContainsKey("Resources")
                        ? (Dictionary<string, decimal>)playerProfile["Resources"]
                        : new Dictionary<string, decimal>(),
                    ProductionRates = productionData.Where(kvp => kvp.Key.EndsWith("PerHour"))
                        .ToDictionary(kvp => kvp.Key.Replace("PerHour", ""), kvp => Convert.ToDecimal(kvp.Value)),
                    StorageCapacity = new Dictionary<string, decimal>
                    {
                        ["Wood"] = 100000,
                        ["Stone"] = 100000,
                        ["Iron"] = 100000,
                        ["Food"] = 100000,
                        ["Gold"] = 50000
                    },
                    ProtectedAmounts = new Dictionary<string, decimal>
                    {
                        ["Wood"] = 10000,
                        ["Stone"] = 10000,
                        ["Iron"] = 10000,
                        ["Food"] = 10000,
                        ["Gold"] = 5000
                    },
                    LastCalculated = DateTime.UtcNow
                };

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving resource status for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to retrieve resource status",
                    Code = "RESOURCE_STATUS_ERROR"
                });
            }
        }

        /// <summary>
        /// Collects accumulated resources from production buildings
        /// </summary>
        /// <returns>Resource collection result with amounts collected</returns>
        [HttpPost("resources/collect")]
        [ProducesResponseType(typeof(ResourceCollectionResponseDto), 200)]
        public async Task<IActionResult> CollectResources()
        {
            try
            {
                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var collectionResult = await _playerService.CollectResourcesAsync(playerId, kingdomId);

                var success = collectionResult.ContainsKey("ResourcesGained");
                var resourcesCollected = success ? (Dictionary<string, long>)collectionResult["ResourcesGained"] : new Dictionary<string, long>();
                var currentBalances = success ? (Dictionary<string, long>)collectionResult["NewResourceTotals"] : new Dictionary<string, long>();

                var response = new ResourceCollectionResponseDto
                {
                    PlayerId = playerId,
                    ResourcesCollected = resourcesCollected,
                    CurrentBalances = currentBalances,
                    ProductionRates = success && collectionResult.ContainsKey("ProductionRates")
                        ? ((Dictionary<string, object>)collectionResult["ProductionRates"])
                            .ToDictionary(kvp => kvp.Key, kvp => Convert.ToDecimal(kvp.Value))
                        : new Dictionary<string, decimal>(),
                    VipBonuses = new Dictionary<string, object>(),
                    AllianceBonuses = new Dictionary<string, object>(),
                    Success = success,
                    CollectionTime = DateTime.UtcNow,
                    NextCollectionTime = DateTime.UtcNow.AddHours(1)
                };

                _logger.LogInformation("Resources collected successfully for Player {PlayerId}", playerId);
                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error collecting resources for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to collect resources",
                    Code = "RESOURCE_COLLECTION_ERROR"
                });
            }
        }

        /// <summary>
        /// Spends resources for various game actions with validation
        /// </summary>
        /// <param name="request">Resource spending parameters</param>
        /// <returns>Resource spending result with validation</returns>
        [HttpPost("resources/spend")]
        [ProducesResponseType(typeof(ResourceSpendingResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        public async Task<IActionResult> SpendResources([FromBody] ResourceSpendingRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid resource spending request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var (success, remainingResources, validationMessage) =
                    await _playerService.SpendResourcesAsync(
                        playerId, kingdomId, request.ResourcesToSpend, request.SpendingCategory);

                if (!success)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Resource spending failed - insufficient resources or invalid spending reason",
                        Code = "SPENDING_FAILED"
                    });
                }

                var response = new ResourceSpendingResponseDto
                {
                    PlayerId = playerId,
                    ResourcesSpent = request.ResourcesToSpend,
                    RemainingBalances = remainingResources,
                    SpendingCategory = request.SpendingCategory,
                    ItemsReceived = new Dictionary<string, object> { ["Item"] = request.TargetItem },
                    CostReductions = new Dictionary<string, decimal>(),
                    Success = success,
                    TransactionId = Guid.NewGuid().ToString(),
                    SpendingTime = DateTime.UtcNow,
                    SpendingAnalytics = new Dictionary<string, object> { ["ValidationMessage"] = validationMessage }
                };

                _logger.LogInformation("Resources spent successfully for Player {PlayerId} - Category: {Category}",
                    playerId, request.SpendingCategory);

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error spending resources for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to spend resources",
                    Code = "RESOURCE_SPENDING_ERROR"
                });
            }
        }

        #endregion

        #region Combat Integration

        /// <summary>
        /// Prepares player for combat with troop validation and march setup
        /// </summary>
        /// <param name="request">Combat preparation parameters</param>
        /// <returns>Combat preparation result with march details</returns>
        [HttpPost("combat/prepare")]
        [ProducesResponseType(typeof(CombatPreparationResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        public async Task<IActionResult> PrepareCombat([FromBody] CombatPreparationRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid combat preparation request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var (canMarch, marchDetails, estimatedArrival, warnings) =
                    await _playerService.PrepareCombatMarchAsync(
                        playerId, kingdomId, request.ArmyComposition, request.CombatType);

                if (!canMarch)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Combat preparation failed - invalid troop composition or target",
                        Code = "PREPARATION_FAILED",
                        Details = new Dictionary<string, object> { ["Warnings"] = warnings }
                    });
                }

                var response = new CombatPreparationResponseDto
                {
                    PlayerId = playerId,
                    CombatType = request.CombatType,
                    MarchDetails = marchDetails,
                    EstimatedArrival = estimatedArrival,
                    TroopComposition = request.ArmyComposition,
                    DragonIncluded = !string.IsNullOrEmpty(request.DragonId),
                    PreparationWarnings = warnings,
                    ResourceCosts = new Dictionary<string, long>(),
                    PreparationTime = DateTime.UtcNow,
                    PreparationData = new Dictionary<string, object> { ["CanMarch"] = canMarch }
                };

                _logger.LogInformation("Combat prepared successfully for Player {PlayerId} - Type: {CombatType}",
                    playerId, request.CombatType);

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error preparing combat for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to prepare combat",
                    Code = "COMBAT_PREPARATION_ERROR"
                });
            }
        }

        /// <summary>
        /// Processes combat results and updates player statistics
        /// </summary>
        /// <param name="request">Combat result processing parameters</param>
        /// <returns>Combat result processing outcome</returns>
        [HttpPost("combat/process-results")]
        [ProducesResponseType(typeof(CombatResultsResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        public async Task<IActionResult> ProcessCombatResults([FromBody] CombatResultsRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid combat results request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var playerUpdates = await _playerService.ProcessCombatResultsAsync(
                    playerId, kingdomId, request.CombatResults);

                var response = new CombatResultsResponseDto
                {
                    PlayerId = playerId,
                    CombatLogId = request.CombatLogId,
                    ResultsSummary = playerUpdates,
                    PlayerStatUpdates = playerUpdates,
                    ExperienceGained = (long)playerUpdates.GetValueOrDefault("ExperienceGained", 0L),
                    PowerChanges = (long)playerUpdates.GetValueOrDefault("PowerLost", 0L),
                    ProcessingTime = DateTime.UtcNow,
                    ResultsData = playerUpdates
                };

                _logger.LogInformation("Combat results processed successfully for Player {PlayerId}", playerId);
                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing combat results for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to process combat results",
                    Code = "COMBAT_RESULTS_ERROR"
                });
            }
        }

        #endregion

        #region Alliance Integration

        /// <summary>
        /// Processes alliance join request or invitation
        /// </summary>
        /// <param name="request">Alliance join parameters</param>
        /// <returns>Alliance join result with benefits and privileges</returns>
        [HttpPost("alliance/join")]
        [ProducesResponseType(typeof(AllianceJoinResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        [ProducesResponseType(typeof(ErrorResponseDto), 409)]
        public async Task<IActionResult> JoinAlliance([FromBody] AllianceJoinRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid alliance join request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var (success, allianceDetails, newPrivileges) =
                    await _playerService.ProcessAllianceJoinAsync(
                        playerId, kingdomId, request.AllianceId, isInvitation: false);

                if (!success)
                {
                    return Conflict(new ErrorResponseDto
                    {
                        Message = "Alliance join failed - player already in alliance, alliance full, or invitation invalid",
                        Code = "JOIN_FAILED"
                    });
                }

                var response = new AllianceJoinResponseDto
                {
                    PlayerId = playerId,
                    AllianceId = request.AllianceId,
                    AllianceName = (string)allianceDetails.GetValueOrDefault("Name", "Unknown"),
                    Success = success,
                    MembershipStatus = "Accepted",
                    AssignedRole = "Member",
                    AllianceBenefits = allianceDetails,
                    ResearchBonuses = new Dictionary<string, decimal>(),
                    WelcomeMessage = $"Welcome to {allianceDetails.GetValueOrDefault("Name", "the alliance")}!",
                    JoinTime = DateTime.UtcNow,
                    IntegrationData = new Dictionary<string, object> { ["NewPrivileges"] = newPrivileges }
                };

                _logger.LogInformation("Player {PlayerId} successfully joined alliance {AllianceId}",
                    playerId, request.AllianceId);

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing alliance join for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to join alliance",
                    Code = "ALLIANCE_JOIN_ERROR"
                });
            }
        }

        /// <summary>
        /// Processes alliance leave with benefit adjustments
        /// </summary>
        /// <param name="request">Alliance leave parameters</param>
        /// <returns>Alliance leave result with benefit adjustments</returns>
        [HttpPost("alliance/leave")]
        [ProducesResponseType(typeof(AllianceLeaveResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        public async Task<IActionResult> LeaveAlliance([FromBody] AllianceLeaveRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid alliance leave request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var (success, benefitsLost, territoryEviction) =
                    await _playerService.ProcessAllianceLeaveAsync(
                        playerId, kingdomId, request.LeaveReason ?? "Voluntary leave");

                if (!success)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Alliance leave failed - player not in alliance or invalid reason",
                        Code = "LEAVE_FAILED"
                    });
                }

                var response = new AllianceLeaveResponseDto
                {
                    PlayerId = playerId,
                    Success = success,
                    LeaveReason = request.LeaveReason ?? "Voluntary leave",
                    BenefitsLost = benefitsLost,
                    TerritoryEvicted = territoryEviction,
                    FormerAllianceId = null, // Would be set from player data
                    FormerAllianceName = "Former Alliance",
                    LeaveTime = DateTime.UtcNow,
                    LeaveData = new Dictionary<string, object> { ["TerritoryEviction"] = territoryEviction }
                };

                _logger.LogInformation("Player {PlayerId} left alliance - Reason: {Reason}",
                    playerId, request.LeaveReason);

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing alliance leave for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to leave alliance",
                    Code = "ALLIANCE_LEAVE_ERROR"
                });
            }
        }

        #endregion

        #region Player Progression and Achievements

        /// <summary>
        /// Processes experience gain and level progression
        /// </summary>
        /// <param name="request">Experience processing parameters</param>
        /// <returns>Experience processing result with level progression</returns>
        [HttpPost("experience/process")]
        [ProducesResponseType(typeof(ExperienceProcessingResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        public async Task<IActionResult> ProcessExperience([FromBody] ExperienceProcessingRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid experience processing request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var (levelUp, newLevel, levelRewards) =
                    await _playerService.ProcessExperienceGainAsync(
                        playerId, kingdomId, (long)request.ExperienceAmount, request.Source ?? request.ExperienceType);

                var response = new ExperienceProcessingResponseDto
                {
                    PlayerId = playerId,
                    ExperienceGained = (long)request.ExperienceAmount,
                    PreviousLevel = levelUp ? Math.Max(1, newLevel - 1) : newLevel,
                    NewLevel = newLevel,
                    LeveledUp = levelUp,
                    TotalExperience = 0, // Would be calculated from player data
                    ExperienceToNextLevel = 1000, // Placeholder
                    LevelUpRewards = levelRewards,
                    UnlockedFeatures = new List<Dictionary<string, object>>(),
                    ExperienceMultipliers = new Dictionary<string, decimal> { ["Base"] = 1.0m },
                    ExperienceSource = request.Source ?? request.ExperienceType,
                    ProcessingTime = DateTime.UtcNow,
                    ProgressionData = new Dictionary<string, object> { ["LevelUp"] = levelUp }
                };

                _logger.LogInformation("Experience processed for Player {PlayerId} - Gained: {Experience} from {Source}",
                    playerId, request.ExperienceAmount, request.Source);

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing experience for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to process experience",
                    Code = "EXPERIENCE_ERROR"
                });
            }
        }

        /// <summary>
        /// Retrieves achievement progress and unlocked achievements
        /// </summary>
        /// <returns>Achievement status and progress information</returns>
        [HttpGet("achievements")]
        [ProducesResponseType(typeof(AchievementsResponseDto), 200)]
        public async Task<IActionResult> GetAchievements()
        {
            try
            {
                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                // Placeholder achievements data - would come from achievement system
                var response = new AchievementsResponseDto
                {
                    PlayerId = playerId,
                    RecentAchievements = new List<Dictionary<string, object>>(),
                    CompletedAchievements = new List<Dictionary<string, object>>(),
                    InProgressAchievements = new List<Dictionary<string, object>>(),
                    CategoryProgress = new Dictionary<string, object>(),
                    TotalAchievementPoints = 0,
                    PendingRewards = new List<Dictionary<string, object>>(),
                    AvailableTitles = new List<Dictionary<string, object>>(),
                    CurrentTitle = null,
                    LeaderboardRank = null,
                    LastUpdated = DateTime.UtcNow,
                    AchievementSystemData = new Dictionary<string, object>()
                };

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving achievements for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to retrieve achievements",
                    Code = "ACHIEVEMENTS_ERROR"
                });
            }
        }

        #endregion

        #region Anti-Exploitation and Validation

        /// <summary>
        /// Validates player actions for potential exploitation or cheating
        /// </summary>
        /// <param name="request">Action validation parameters</param>
        /// <returns>Validation result and risk assessment</returns>
        [HttpPost("validate-action")]
        [ProducesResponseType(typeof(ActionValidationResponseDto), 200)]
        [ProducesResponseType(typeof(ErrorResponseDto), 400)]
        public async Task<IActionResult> ValidateAction([FromBody] ActionValidationRequestDto request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(new ErrorResponseDto
                    {
                        Message = "Invalid action validation request",
                        Code = "INVALID_REQUEST",
                        ValidationErrors = ModelState.ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage).ToArray())
                    });
                }

                var (playerId, kingdomId) = GetAuthenticatedPlayer();

                var (isValid, warnings, riskFactors) =
                    await _playerService.ValidatePlayerActionAsync(
                        playerId, kingdomId, request.ActionType, request.ActionParameters);

                var response = new ActionValidationResponseDto
                {
                    PlayerId = playerId,
                    ActionType = request.ActionType,
                    IsValid = isValid,
                    ValidationErrors = warnings,
                    Requirements = new Dictionary<string, object>(),
                    PlayerStatus = new Dictionary<string, object>(),
                    ActionCosts = new Dictionary<string, object>(),
                    ExpectedBenefits = new Dictionary<string, object>(),
                    CooldownInfo = null,
                    BalanceValidation = riskFactors,
                    ValidationTime = DateTime.UtcNow,
                    ValidationMetadata = new Dictionary<string, object> { ["RiskFactors"] = riskFactors }
                };

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error validating action for Player {PlayerId}", GetAuthenticatedPlayer().PlayerId);
                return StatusCode(500, new ErrorResponseDto
                {
                    Message = "Failed to validate action",
                    Code = "VALIDATION_ERROR"
                });
            }
        }

        #endregion

        #region Helper Methods

        /// <summary>
        /// Extracts authenticated player information from JWT claims
        /// </summary>
        /// <returns>Player ID and Kingdom ID from authentication context</returns>
        /// <exception cref="UnauthorizedAccessException">Thrown when authentication claims are invalid</exception>
        private (int PlayerId, int KingdomId) GetAuthenticatedPlayer()
        {
            var playerIdClaim = User.FindFirst("player_id")?.Value;
            var kingdomIdClaim = User.FindFirst("kingdom_id")?.Value;

            if (string.IsNullOrEmpty(playerIdClaim) || string.IsNullOrEmpty(kingdomIdClaim))
            {
                throw new UnauthorizedAccessException("Invalid authentication claims - player or kingdom not found");
            }

            if (!int.TryParse(playerIdClaim, out int playerId) ||
                !int.TryParse(kingdomIdClaim, out int kingdomId))
            {
                throw new UnauthorizedAccessException("Invalid authentication claims - unable to parse player or kingdom ID");
            }

            return (playerId, kingdomId);
        }

        /// <summary>
        /// Converts coordinate tuple to dictionary format for API responses
        /// </summary>
        /// <param name="coordinates">Coordinate tuple (X, Y)</param>
        /// <returns>Dictionary with X and Y coordinate values</returns>
        private Dictionary<string, decimal> GetLocationDictionary(ValueTuple<int, int> coordinates)
        {
            return new Dictionary<string, decimal>
            {
                ["X"] = coordinates.Item1,
                ["Y"] = coordinates.Item2
            };
        }

        #endregion
    }
}

// Additional Response DTOs that were missing from the project:

namespace ShadowedRealms.Shared.DTOs.Player
{
    /// <summary>
    /// Response DTO for combat preparation operations
    /// </summary>
    public class CombatPreparationResponseDto
    {
        public int PlayerId { get; set; }
        public string CombatType { get; set; } = string.Empty;
        public Dictionary<string, object> MarchDetails { get; set; } = new();
        public DateTime EstimatedArrival { get; set; }
        public Dictionary<string, int> TroopComposition { get; set; } = new();
        public bool DragonIncluded { get; set; }
        public List<string> PreparationWarnings { get; set; } = new();
        public Dictionary<string, long> ResourceCosts { get; set; } = new();
        public DateTime PreparationTime { get; set; }
        public Dictionary<string, object> PreparationData { get; set; } = new();
    }

    /// <summary>
    /// Request DTO for combat results processing
    /// </summary>
    public class CombatResultsRequestDto
    {
        public int CombatLogId { get; set; }
        public Dictionary<string, object> CombatResults { get; set; } = new();
    }

    /// <summary>
    /// Response DTO for combat results processing
    /// </summary>
    public class CombatResultsResponseDto
    {
        public int PlayerId { get; set; }
        public int CombatLogId { get; set; }
        public Dictionary<string, object> ResultsSummary { get; set; } = new();
        public Dictionary<string, object> PlayerStatUpdates { get; set; } = new();
        public long ExperienceGained { get; set; }
        public long PowerChanges { get; set; }
        public DateTime ProcessingTime { get; set; }
        public Dictionary<string, object> ResultsData { get; set; } = new();
    }

    /// <summary>
    /// Response DTO for alliance leave operations
    /// </summary>
    public class AllianceLeaveResponseDto
    {
        public int PlayerId { get; set; }
        public bool Success { get; set; }
        public string? LeaveReason { get; set; }
        public Dictionary<string, object> BenefitsLost { get; set; } = new();
        public bool TerritoryEvicted { get; set; }
        public int? FormerAllianceId { get; set; }
        public string? FormerAllianceName { get; set; }
        public DateTime LeaveTime { get; set; }
        public Dictionary<string, object> LeaveData { get; set; } = new();
    }
}