using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RR3CommunityServer.Data;
using RR3CommunityServer.Models;
using static RR3CommunityServer.Data.RR3DbContext;

namespace RR3CommunityServer.Controllers;

[ApiController]
[Route("synergy/[controller]")]
public class ProgressionController : ControllerBase
{
    private readonly RR3DbContext _context;
    private readonly ILogger<ProgressionController> _logger;

    public ProgressionController(RR3DbContext context, ILogger<ProgressionController> logger)
    {
        _context = context;
        _logger = logger;
    }

    /// <summary>
    /// Get player progression data (career, owned cars, upgrades, etc.)
    /// </summary>
    [HttpGet("player/{synergyId}")]
    public async Task<IActionResult> GetPlayerProgression(string synergyId)
    {
        _logger.LogInformation("Getting progression for {SynergyId}", synergyId);

        var user = await _context.Users
            .Include(u => u.OwnedCars)
            .Include(u => u.CareerProgress)
            .FirstOrDefaultAsync(u => u.SynergyId == synergyId);

        if (user == null)
        {
            return NotFound(new { error = "User not found" });
        }

        return Ok(new
        {
            playerId = user.SynergyId,
            level = user.Level ?? 1,
            experience = user.Experience ?? 0,
            gold = user.Gold ?? 0,
            cash = user.Cash ?? 0,
            reputation = user.Reputation ?? 0,
            ownedCars = user.OwnedCars.Select(c => new
            {
                id = c.CarId,
                name = c.CarName,
                manufacturer = c.Manufacturer,
                class_type = c.ClassType,
                performance_rating = c.PerformanceRating,
                upgrade_level = c.UpgradeLevel,
                purchased_upgrades = c.PurchasedUpgrades
            }),
            careerProgress = user.CareerProgress.Select(cp => new
            {
                series = cp.SeriesName,
                eventName = cp.EventName,
                completed = cp.Completed,
                stars = cp.StarsEarned,
                best_time = cp.BestTime
            })
        });
    }

    /// <summary>
    /// Update player progression (complete event, earn XP, etc.)
    /// </summary>
    [HttpPost("player/{synergyId}/update")]
    public async Task<IActionResult>UpdateProgression(string synergyId, [FromBody] ProgressionUpdate update)
    {
        _logger.LogInformation("Updating progression for {SynergyId}", synergyId);

        var user = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == synergyId);
        if (user == null)
        {
            return NotFound(new { error = "User not found" });
        }

        // Update currency
        if (update.GoldEarned.HasValue)
        {
            user.Gold = (user.Gold ?? 0) + update.GoldEarned.Value;
        }

        if (update.CashEarned.HasValue)
        {
            user.Cash = (user.Cash ?? 0) + update.CashEarned.Value;
        }

        // Update XP and level
        if (update.ExperienceEarned.HasValue)
        {
            user.Experience = (user.Experience ?? 0) + update.ExperienceEarned.Value;
            
            // Level up calculation (every 1000 XP = 1 level)
            int newLevel = (user.Experience.Value / 1000) + 1;
            if (newLevel > (user.Level ?? 1))
            {
                user.Level = newLevel;
                // Level up rewards
                user.Gold = (user.Gold ?? 0) + (newLevel * 10); // 10 gold per level
                user.Cash = (user.Cash ?? 0) + (newLevel * 5000); // 5k cash per level
            }
        }

        // Update reputation
        if (update.ReputationEarned.HasValue)
        {
            user.Reputation = (user.Reputation ?? 0) + update.ReputationEarned.Value;
        }

        await _context.SaveChangesAsync();

        return Ok(new
        {
            success = true,
            newGold = user.Gold,
            newCash = user.Cash,
            newExperience = user.Experience,
            newLevel = user.Level,
            newReputation = user.Reputation,
            leveledUp = update.ExperienceEarned.HasValue && (user.Experience.Value / 1000) + 1 > (user.Level ?? 1) - 1
        });
    }

    /// <summary>
    /// Purchase/unlock a car
    /// </summary>
    [HttpPost("car/purchase")]
    public async Task<IActionResult> PurchaseCar([FromBody] CarPurchaseRequest request)
    {
        _logger.LogInformation("Purchasing car {CarId} for {SynergyId}", request.CarId, request.SynergyId);

        var user = await _context.Users
            .Include(u => u.OwnedCars)
            .FirstOrDefaultAsync(u => u.SynergyId == request.SynergyId);

        if (user == null)
        {
            return NotFound(new { error = "User not found" });
        }

        // Check if already owned
        if (user.OwnedCars.Any(c => c.CarId == request.CarId))
        {
            return BadRequest(new { error = "Car already owned" });
        }

        // Get car data from catalog
        var carData = await _context.Cars.FirstOrDefaultAsync(c => c.CarId == request.CarId);
        if (carData == null)
        {
            return NotFound(new { error = "Car not found in catalog" });
        }

        // Check currency (in community server, can make it free or use price)
        int costGold = request.UseGold ? carData.GoldPrice : 0;
        int costCash = !request.UseGold ? carData.CashPrice : 0;

        if (request.UseGold && (user.Gold ?? 0) < costGold)
        {
            return BadRequest(new { error = "Insufficient gold" });
        }

        if (!request.UseGold && (user.Cash ?? 0) < costCash)
        {
            return BadRequest(new { error = "Insufficient cash" });
        }

        // Deduct currency
        if (request.UseGold)
        {
            user.Gold -= costGold;
        }
        else
        {
            user.Cash -= costCash;
        }

        // Add car to garage
        var ownedCar = new OwnedCar
        {
            UserId = user.Id,
            CarId = carData.CarId,
            CarName = carData.Name,
            Manufacturer = carData.Manufacturer,
            ClassType = carData.ClassType,
            PerformanceRating = carData.BasePerformanceRating,
            UpgradeLevel = 0,
            PurchasedUpgrades = "",
            PurchasedAt = DateTime.UtcNow
        };

        _context.OwnedCars.Add(ownedCar);
        await _context.SaveChangesAsync();

        return Ok(new
        {
            success = true,
            carId = ownedCar.CarId,
            carName = ownedCar.CarName,
            goldSpent = costGold,
            cashSpent = costCash,
            remainingGold = user.Gold,
            remainingCash = user.Cash
        });
    }

    /// <summary>
    /// Upgrade a car
    /// </summary>
    [HttpPost("car/upgrade")]
    public async Task<IActionResult> UpgradeCar([FromBody] CarUpgradeRequest request)
    {
        _logger.LogInformation("Upgrading car {CarId} for {SynergyId}: {Upgrade}",
            request.CarId, request.SynergyId, request.UpgradeType);

        var user = await _context.Users
            .Include(u => u.OwnedCars)
            .FirstOrDefaultAsync(u => u.SynergyId == request.SynergyId);

        if (user == null)
        {
            return NotFound(new { error = "User not found" });
        }

        var ownedCar = user.OwnedCars.FirstOrDefault(c => c.CarId == request.CarId);
        if (ownedCar == null)
        {
            return BadRequest(new { error = "Car not owned" });
        }

        // Get upgrade cost
        var upgrade = await _context.CarUpgrades
            .FirstOrDefaultAsync(u => u.CarId == request.CarId && u.UpgradeType == request.UpgradeType);

        if (upgrade == null)
        {
            return NotFound(new { error = "Upgrade not found" });
        }

        // Check if already purchased
        var purchasedUpgrades = ownedCar.PurchasedUpgrades?.Split(',') ?? Array.Empty<string>();
        if (purchasedUpgrades.Contains(request.UpgradeType))
        {
            return BadRequest(new { error = "Upgrade already purchased" });
        }

        // Check currency
        if ((user.Cash ?? 0) < upgrade.CashCost)
        {
            return BadRequest(new { error = "Insufficient cash" });
        }

        // Apply upgrade
        user.Cash -= upgrade.CashCost;
        ownedCar.UpgradeLevel++;
        ownedCar.PerformanceRating += upgrade.PerformanceIncrease;
        
        var newUpgrades = purchasedUpgrades.Append(request.UpgradeType).ToArray();
        ownedCar.PurchasedUpgrades = string.Join(",", newUpgrades);

        await _context.SaveChangesAsync();

        return Ok(new
        {
            success = true,
            upgradeType = request.UpgradeType,
            cashSpent = upgrade.CashCost,
            newPerformanceRating = ownedCar.PerformanceRating,
            newUpgradeLevel = ownedCar.UpgradeLevel,
            remainingCash = user.Cash
        });
    }

    /// <summary>
    /// Complete a career event
    /// </summary>
    [HttpPost("career/complete")]
    public async Task<IActionResult> CompleteCareerEvent([FromBody] CareerEventCompletion completion)
    {
        _logger.LogInformation("Completing career event {Event} for {SynergyId}",
            completion.EventName, completion.SynergyId);

        var user = await _context.Users
            .Include(u => u.CareerProgress)
            .FirstOrDefaultAsync(u => u.SynergyId == completion.SynergyId);

        if (user == null)
        {
            return NotFound(new { error = "User not found" });
        }

        // Find or create progress entry
        var progress = user.CareerProgress.FirstOrDefault(cp =>
            cp.SeriesName == completion.SeriesName &&
            cp.EventName == completion.EventName);

        if (progress == null)
        {
            progress = new CareerProgress
            {
                UserId = user.Id,
                SeriesName = completion.SeriesName,
                EventName = completion.EventName,
                Completed = false,
                StarsEarned = 0
            };
            _context.CareerProgress.Add(progress);
        }

        // Update progress
        progress.Completed = true;
        progress.StarsEarned = Math.Max(progress.StarsEarned, completion.StarsEarned);
        progress.BestTime = progress.BestTime == 0 ? completion.RaceTime :
            Math.Min(progress.BestTime, completion.RaceTime);
        progress.CompletedAt = DateTime.UtcNow;

        // Award rewards
        int goldReward = completion.StarsEarned * 10; // 10 gold per star
        int cashReward = completion.StarsEarned * 2000; // 2000 cash per star
        int xpReward = completion.StarsEarned * 100; // 100 XP per star

        user.Gold = (user.Gold ?? 0) + goldReward;
        user.Cash = (user.Cash ?? 0) + cashReward;
        user.Experience = (user.Experience ?? 0) + xpReward;

        await _context.SaveChangesAsync();

        return Ok(new
        {
            success = true,
            stars = completion.StarsEarned,
            goldEarned = goldReward,
            cashEarned = cashReward,
            xpEarned = xpReward,
            bestTime = progress.BestTime,
            totalGold = user.Gold,
            totalCash = user.Cash,
            totalExperience = user.Experience
        });
    }
}
