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

namespace RR3CommunityServer.Controllers;

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

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

    /// <summary>
    /// Get daily reward status for a user
    /// </summary>
    [HttpGet("daily/{synergyId}")]
    public async Task<IActionResult> GetDailyReward(string synergyId)
    {
        _logger.LogInformation("Getting daily reward for {SynergyId}", synergyId);

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

        var today = DateTime.UtcNow.Date;
        var reward = await _context.DailyRewards
            .FirstOrDefaultAsync(r => r.UserId == user.Id && r.RewardDate.Date == today);

        if (reward == null)
        {
            // Create new daily reward
            reward = new DailyReward
            {
                UserId = user.Id,
                RewardDate = DateTime.UtcNow,
                GoldAmount = 50, // Daily gold reward
                CashAmount = 5000, // Daily cash reward
                Claimed = false,
                Streak = await CalculateStreak(user.Id)
            };

            _context.DailyRewards.Add(reward);
            await _context.SaveChangesAsync();
        }

        return Ok(new
        {
            available = !reward.Claimed,
            gold = reward.GoldAmount,
            cash = reward.CashAmount,
            streak = reward.Streak,
            nextRewardIn = reward.Claimed ? (24 - (DateTime.UtcNow - reward.RewardDate).TotalHours) : 0
        });
    }

    /// <summary>
    /// Claim daily reward
    /// </summary>
    [HttpPost("daily/{synergyId}/claim")]
    public async Task<IActionResult> ClaimDailyReward(string synergyId)
    {
        _logger.LogInformation("Claiming daily reward for {SynergyId}", synergyId);

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

        var today = DateTime.UtcNow.Date;
        var reward = await _context.DailyRewards
            .FirstOrDefaultAsync(r => r.UserId == user.Id && r.RewardDate.Date == today);

        if (reward == null || reward.Claimed)
        {
            return BadRequest(new { error = "No reward available to claim" });
        }

        // Mark as claimed
        reward.Claimed = true;
        reward.ClaimedAt = DateTime.UtcNow;

        // Update user's gold and cash
        if (user.Gold == null) user.Gold = 0;
        if (user.Cash == null) user.Cash = 0;

        user.Gold += reward.GoldAmount;
        user.Cash += reward.CashAmount;

        await _context.SaveChangesAsync();

        return Ok(new
        {
            success = true,
            goldEarned = reward.GoldAmount,
            cashEarned = reward.CashAmount,
            totalGold = user.Gold,
            totalCash = user.Cash,
            streak = reward.Streak
        });
    }

    /// <summary>
    /// Purchase gold with real money (free in community server)
    /// </summary>
    /// <summary>
    /// Purchase gold - FREE in community server per EA agreement
    /// IMPORTANT: No real money transactions allowed!
    /// </summary>
    [HttpPost("gold/purchase")]
    public async Task<IActionResult> PurchaseGold([FromBody] GoldPurchaseRequest request)
    {
        _logger.LogInformation("Processing gold purchase for {SynergyId}: {Amount} gold (FREE - community server)", 
            request.SynergyId, request.GoldAmount);

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

        // ⚖️ EA COMPLIANCE: All gold purchases are FREE in community server!
        // Per EA agreement: No real money in-app purchases allowed
        if (user.Gold == null) user.Gold = 0;
        user.Gold += request.GoldAmount;

        // Log the purchase (for tracking, not billing)
        var purchase = new Purchase
        {
            SynergyId = request.SynergyId,
            UserId = user.Id,
            ItemId = $"gold_{request.GoldAmount}",
            Sku = request.Sku ?? $"com.ea.rr3.gold_{request.GoldAmount}",
            OrderId = Guid.NewGuid().ToString(),
            PurchaseTime = DateTime.UtcNow,
            Token = Guid.NewGuid().ToString(),
            Price = 0, // ⚖️ MUST BE 0 - EA COMPLIANCE
            Status = "approved"
        };

        _context.Purchases.Add(purchase);
        await _context.SaveChangesAsync();

        return Ok(new
        {
            success = true,
            goldPurchased = request.GoldAmount,
            totalGold = user.Gold,
            orderId = purchase.OrderId,
            message = "Gold added to your account (FREE in community server!)"
        });
    }

    /// <summary>
    /// Get time trial events
    /// </summary>
    [HttpGet("timetrials")]
    public async Task<IActionResult> GetTimeTrials()
    {
        _logger.LogInformation("Getting time trial events");

        var trials = await _context.TimeTrials
            .Where(t => t.Active)
            .OrderBy(t => t.StartDate)
            .ToListAsync();

        return Ok(new
        {
            events = trials.Select(t => new
            {
                id = t.Id,
                name = t.Name,
                track = t.TrackName,
                car = t.CarName,
                startDate = t.StartDate,
                endDate = t.EndDate,
                goldReward = t.GoldReward,
                cashReward = t.CashReward,
                targetTime = t.TargetTime,
                timeRemaining = (t.EndDate - DateTime.UtcNow).TotalSeconds,
                isActive = t.StartDate <= DateTime.UtcNow && t.EndDate >= DateTime.UtcNow
            })
        });
    }

    /// <summary>
    /// Get specific time trial details
    /// </summary>
    [HttpGet("timetrials/{trialId}")]
    public async Task<IActionResult> GetTimeTrial(int trialId)
    {
        _logger.LogInformation("Getting time trial {TrialId}", trialId);

        var trial = await _context.TimeTrials.FindAsync(trialId);
        if (trial == null)
        {
            return NotFound(new { error = "Time trial not found" });
        }

        // Get total participants
        var participantCount = await _context.TimeTrialResults
            .Where(r => r.TimeTrialId == trialId)
            .Select(r => r.UserId)
            .Distinct()
            .CountAsync();

        // Get fastest time
        var fastestTime = await _context.TimeTrialResults
            .Where(r => r.TimeTrialId == trialId)
            .OrderBy(r => r.TimeSeconds)
            .FirstOrDefaultAsync();

        var response = new
        {
            id = trial.Id,
            name = trial.Name,
            trackName = trial.TrackName,
            carName = trial.CarName,
            targetTime = trial.TargetTime,
            goldReward = trial.GoldReward,
            cashReward = trial.CashReward,
            startDate = trial.StartDate,
            endDate = trial.EndDate,
            active = trial.Active,
            timeRemaining = (trial.EndDate - DateTime.UtcNow).TotalSeconds,
            participants = participantCount,
            fastestTime = fastestTime?.TimeSeconds,
            fastestPlayer = fastestTime != null ? 
                (await _context.Users.FindAsync(fastestTime.UserId))?.SynergyId : null
        };

        return Ok(response);
    }

    /// <summary>
    /// Get player's time trial results
    /// </summary>
    [HttpGet("timetrials/player/{synergyId}/results")]
    public async Task<IActionResult> GetPlayerTimeTrialResults(string synergyId, [FromQuery] int? trialId = null)
    {
        _logger.LogInformation("Getting time trial results for {SynergyId}", synergyId);

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

        var query = _context.TimeTrialResults
            .Include(r => r.TimeTrial)
            .Where(r => r.UserId == user.Id);

        // Filter by specific trial if provided
        if (trialId.HasValue)
        {
            query = query.Where(r => r.TimeTrialId == trialId.Value);
        }

        var results = await query
            .OrderByDescending(r => r.SubmittedAt)
            .ToListAsync();

        var response = new
        {
            synergyId = synergyId,
            totalAttempts = results.Count,
            totalGoldEarned = results.Sum(r => r.GoldEarned),
            totalCashEarned = results.Sum(r => r.CashEarned),
            targetsBeat = results.Count(r => r.BeatTarget),
            results = results.Select(r => new
            {
                trialId = r.TimeTrialId,
                trialName = r.TimeTrial?.Name,
                timeSeconds = r.TimeSeconds,
                beatTarget = r.BeatTarget,
                goldEarned = r.GoldEarned,
                cashEarned = r.CashEarned,
                submittedAt = r.SubmittedAt
            }).ToList()
        };

        return Ok(response);
    }

    /// <summary>
    /// Claim time trial reward (bonus for completing)
    /// </summary>
    [HttpPost("timetrials/{trialId}/claim")]
    public async Task<IActionResult> ClaimTimeTrialReward(int trialId, [FromBody] ClaimRewardRequest request)
    {
        _logger.LogInformation("Claiming time trial reward for {SynergyId}, trial {TrialId}", 
            request.SynergyId, trialId);

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

        var trial = await _context.TimeTrials.FindAsync(trialId);
        if (trial == null || !trial.Active)
        {
            return NotFound(new { error = "Time trial not found or inactive" });
        }

        // Check if player has a result for this trial
        var bestResult = await _context.TimeTrialResults
            .Where(r => r.UserId == user.Id && r.TimeTrialId == trialId)
            .OrderBy(r => r.TimeSeconds)
            .FirstOrDefaultAsync();

        if (bestResult == null)
        {
            return BadRequest(new { error = "No results found for this time trial" });
        }

        // Check if already claimed (could store in separate ClaimedRewards table)
        // For now, just give completion bonus
        int bonusGold = bestResult.BeatTarget ? 100 : 50; // Bonus for participating
        int bonusCash = bestResult.BeatTarget ? 10000 : 5000;

        user.Gold = (user.Gold ?? 0) + bonusGold;
        user.Cash = (user.Cash ?? 0) + bonusCash;

        await _context.SaveChangesAsync();

        return Ok(new
        {
            success = true,
            bonusGold = bonusGold,
            bonusCash = bonusCash,
            totalGold = user.Gold,
            totalCash = user.Cash,
            message = bestResult.BeatTarget ? 
                "🏆 Completion bonus claimed!" : 
                "Thanks for participating! Keep racing!"
        });
    }

    /// <summary>
    /// Submit time trial result
    /// </summary>
    [HttpPost("timetrials/{trialId}/submit")]
    public async Task<IActionResult> SubmitTimeTrial(int trialId, [FromBody] TimeTrialSubmission submission)
    {
        _logger.LogInformation("Submitting time trial {TrialId} for {SynergyId}: {Time}s",
            trialId, submission.SynergyId, submission.TimeSeconds);

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

        var trial = await _context.TimeTrials.FindAsync(trialId);
        if (trial == null || !trial.Active)
        {
            return NotFound(new { error = "Time trial not found or inactive" });
        }

        // Check if beat target time
        bool beatTarget = submission.TimeSeconds <= trial.TargetTime;
        int goldEarned = beatTarget ? trial.GoldReward : 0;
        int cashEarned = beatTarget ? trial.CashReward : trial.CashReward / 2; // Half cash for participation

        // Check for personal best
        var personalRecord = await _context.PersonalRecords
            .FirstOrDefaultAsync(pr => pr.SynergyId == submission.SynergyId &&
                                      pr.RecordType == "TimeTrial" &&
                                      pr.RecordCategory == trialId.ToString());

        bool isNewPersonalBest = false;
        double? previousBestTime = null;
        double? improvement = null;

        if (personalRecord == null)
        {
            // First attempt - create new personal record
            isNewPersonalBest = true;
            personalRecord = new Data.PersonalRecord
            {
                SynergyId = submission.SynergyId,
                RecordType = "TimeTrial",
                RecordCategory = trialId.ToString(),
                TrackName = trial.TrackName,
                CarName = submission.CarName,
                BestTimeSeconds = submission.TimeSeconds,
                AchievedAt = DateTime.UtcNow,
                TotalAttempts = 1
            };
            _context.PersonalRecords.Add(personalRecord);
        }
        else
        {
            // Update attempt count
            personalRecord.TotalAttempts++;

            // Check if this is a new personal best
            if (submission.TimeSeconds < personalRecord.BestTimeSeconds)
            {
                isNewPersonalBest = true;
                previousBestTime = personalRecord.BestTimeSeconds;
                improvement = personalRecord.BestTimeSeconds - submission.TimeSeconds;

                personalRecord.BestTimeSeconds = submission.TimeSeconds;
                personalRecord.AchievedAt = DateTime.UtcNow;
                personalRecord.ImprovementSeconds = improvement;
                personalRecord.CarName = submission.CarName;
            }
        }

        // Save result
        var result = new TimeTrialResult
        {
            UserId = user.Id,
            TimeTrialId = trialId,
            TimeSeconds = submission.TimeSeconds,
            SubmittedAt = DateTime.UtcNow,
            BeatTarget = beatTarget,
            GoldEarned = goldEarned,
            CashEarned = cashEarned
        };

        _context.TimeTrialResults.Add(result);

        // Add/update leaderboard entry if personal best
        if (isNewPersonalBest)
        {
            var leaderboardEntry = new Data.LeaderboardEntry
            {
                SynergyId = submission.SynergyId,
                PlayerName = user.SynergyId,
                RecordType = "TimeTrial",
                RecordCategory = trialId.ToString(),
                TrackName = trial.TrackName,
                CarName = submission.CarName,
                TimeSeconds = submission.TimeSeconds,
                SubmittedAt = DateTime.UtcNow
            };
            _context.LeaderboardEntries.Add(leaderboardEntry);
        }

        // Award currency
        if (user.Gold == null) user.Gold = 0;
        if (user.Cash == null) user.Cash = 0;
        user.Gold += goldEarned;
        user.Cash += cashEarned;

        // Bonus rewards for personal best
        if (isNewPersonalBest && previousBestTime.HasValue)
        {
            int bonusGold = 50; // Bonus for improving
            user.Gold += bonusGold;
            goldEarned += bonusGold;
        }

        await _context.SaveChangesAsync();

        // Calculate global rank
        int globalRank = await _context.LeaderboardEntries
            .Where(e => e.RecordType == "TimeTrial" &&
                       e.RecordCategory == trialId.ToString() &&
                       e.TimeSeconds < submission.TimeSeconds)
            .CountAsync() + 1;

        // Check if this is a new global record
        bool isNewGlobalRecord = globalRank == 1;

        return Ok(new RecordSubmissionResponse
        {
            Success = true,
            IsNewPersonalBest = isNewPersonalBest,
            IsNewGlobalRecord = isNewGlobalRecord,
            GlobalRank = globalRank,
            PreviousBestTime = previousBestTime,
            Improvement = improvement,
            GoldEarned = goldEarned,
            CashEarned = cashEarned
        });
    }

    private async Task<int> CalculateStreak(int userId)
    {
        var rewards = await _context.DailyRewards
            .Where(r => r.UserId == userId && r.Claimed)
            .OrderByDescending(r => r.RewardDate)
            .ToListAsync();

        int streak = 0;
        var currentDate = DateTime.UtcNow.Date;

        foreach (var reward in rewards)
        {
            if (reward.RewardDate.Date == currentDate.AddDays(-streak))
            {
                streak++;
            }
            else
            {
                break;
            }
        }

        return streak;
    }
}

public class GoldPurchaseRequest
{
    public string SynergyId { get; set; } = string.Empty;
    public int GoldAmount { get; set; }
    public string? Sku { get; set; }
}

public class TimeTrialSubmission
{
    public string SynergyId { get; set; } = string.Empty;
    public double TimeSeconds { get; set; }
    public string? CarName { get; set; }
}

public class ClaimRewardRequest
{
    public string SynergyId { get; set; } = string.Empty;
}
