using DramaLing.Api.Data;
using DramaLing.Api.Models.Configuration;
using DramaLing.Api.Models.DTOs.SpacedRepetition;
using DramaLing.Api.Models.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

namespace DramaLing.Api.Services;

/// <summary>
/// 智能複習間隔重複服務介面
/// </summary>
public interface ISpacedRepetitionService
{
    Task<ReviewResult> ProcessReviewAsync(Guid flashcardId, ReviewRequest request);
    int CalculateCurrentMasteryLevel(Flashcard flashcard);
    Task<List<Flashcard>> GetDueFlashcardsAsync(Guid userId, DateTime? date = null, int limit = 50);
    Task<Flashcard?> GetNextReviewCardAsync(Guid userId);
}

/// <summary>
/// 智能複習間隔重複服務實現 (基於現有SM2Algorithm擴展)
/// </summary>
public class SpacedRepetitionService : ISpacedRepetitionService
{
    private readonly DramaLingDbContext _context;
    private readonly ILogger<SpacedRepetitionService> _logger;
    private readonly SpacedRepetitionOptions _options;

    public SpacedRepetitionService(
        DramaLingDbContext context,
        ILogger<SpacedRepetitionService> logger,
        IOptions<SpacedRepetitionOptions> options)
    {
        _context = context;
        _logger = logger;
        _options = options.Value;
    }

    /// <summary>
    /// 處理復習結果並更新間隔重複算法
    /// </summary>
    public async Task<ReviewResult> ProcessReviewAsync(Guid flashcardId, ReviewRequest request)
    {
        var flashcard = await _context.Flashcards.FindAsync(flashcardId);
        if (flashcard == null)
            throw new ArgumentException($"Flashcard {flashcardId} not found");

        var actualReviewDate = DateTime.Now.Date;
        var overdueDays = Math.Max(0, (actualReviewDate - flashcard.NextReviewDate.Date).Days);

        _logger.LogInformation("Processing review for flashcard {FlashcardId}, word: {Word}, overdue: {OverdueDays} days",
            flashcardId, flashcard.Word, overdueDays);

        // 1. 基於現有SM2Algorithm計算基礎間隔
        var quality = GetQualityFromRequest(request);
        var sm2Input = new SM2Input(quality, flashcard.EasinessFactor, flashcard.Repetitions, flashcard.IntervalDays);
        var sm2Result = SM2Algorithm.Calculate(sm2Input);

        // 2. 應用智能複習系統的增強邏輯
        var enhancedInterval = ApplyEnhancedSpacedRepetitionLogic(sm2Result.IntervalDays, request, overdueDays);

        // 3. 計算表現係數和增長係數
        var performanceFactor = GetPerformanceFactor(request);
        var growthFactor = _options.GrowthFactors.GetGrowthFactor(flashcard.IntervalDays);
        var penaltyFactor = _options.OverduePenalties.GetPenaltyFactor(overdueDays);

        // 4. 更新熟悉度
        var newMasteryLevel = CalculateMasteryLevel(
            flashcard.TimesCorrect + (request.IsCorrect ? 1 : 0),
            flashcard.TimesReviewed + 1,
            enhancedInterval
        );

        // 5. 更新資料庫
        flashcard.EasinessFactor = sm2Result.EasinessFactor;
        flashcard.Repetitions = sm2Result.Repetitions;
        flashcard.IntervalDays = enhancedInterval;
        flashcard.NextReviewDate = actualReviewDate.AddDays(enhancedInterval);
        flashcard.MasteryLevel = newMasteryLevel;
        flashcard.TimesReviewed++;
        if (request.IsCorrect) flashcard.TimesCorrect++;
        flashcard.LastReviewedAt = DateTime.Now;
        flashcard.LastQuestionType = request.QuestionType;
        flashcard.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        return new ReviewResult
        {
            NewInterval = enhancedInterval,
            NextReviewDate = flashcard.NextReviewDate,
            MasteryLevel = newMasteryLevel,
            CurrentMasteryLevel = CalculateCurrentMasteryLevel(flashcard),
            IsOverdue = overdueDays > 0,
            OverdueDays = overdueDays,
            PerformanceFactor = performanceFactor,
            GrowthFactor = growthFactor,
            PenaltyFactor = penaltyFactor
        };
    }

    /// <summary>
    /// 計算當前熟悉度 (考慮記憶衰減)
    /// </summary>
    public int CalculateCurrentMasteryLevel(Flashcard flashcard)
    {
        if (flashcard.LastReviewedAt == null)
            return flashcard.MasteryLevel;

        var daysSinceReview = (DateTime.Now.Date - flashcard.LastReviewedAt.Value.Date).Days;

        if (daysSinceReview <= 0)
            return flashcard.MasteryLevel;

        // 應用記憶衰減
        var decayRate = _options.MemoryDecayRate;
        var maxDecayDays = 30;
        var effectiveDays = Math.Min(daysSinceReview, maxDecayDays);
        var decayFactor = Math.Pow(1 - decayRate, effectiveDays);

        return Math.Max(0, (int)(flashcard.MasteryLevel * decayFactor));
    }

    /// <summary>
    /// 取得到期詞卡列表
    /// </summary>
    public async Task<List<Flashcard>> GetDueFlashcardsAsync(Guid userId, DateTime? date = null, int limit = 50)
    {
        var queryDate = date ?? DateTime.Now.Date;

        var dueCards = await _context.Flashcards
            .Where(f => f.UserId == userId &&
                       !f.IsArchived &&
                       f.NextReviewDate.Date <= queryDate)
            .OrderBy(f => f.NextReviewDate)  // 最逾期的優先
            .ThenByDescending(f => f.MasteryLevel) // 熟悉度低的優先
            .Take(limit)
            .ToListAsync();

        // 初始化WordLevel (如果是舊資料)
        foreach (var card in dueCards.Where(c => c.WordLevel == 0))
        {
            card.WordLevel = CEFRMappingService.GetWordLevel(card.DifficultyLevel);
            if (card.UserLevel == 0)
                card.UserLevel = _options.DefaultUserLevel;
        }

        if (dueCards.Any(c => c.WordLevel != 0 || c.UserLevel != 0))
        {
            await _context.SaveChangesAsync();
        }

        return dueCards;
    }

    /// <summary>
    /// 取得下一張需要復習的詞卡 (最高優先級)
    /// </summary>
    public async Task<Flashcard?> GetNextReviewCardAsync(Guid userId)
    {
        var dueCards = await GetDueFlashcardsAsync(userId, limit: 1);
        return dueCards.FirstOrDefault();
    }

    /// <summary>
    /// 應用增強的間隔重複邏輯 (基於演算法規格書)
    /// </summary>
    private int ApplyEnhancedSpacedRepetitionLogic(int baseInterval, ReviewRequest request, int overdueDays)
    {
        var performanceFactor = GetPerformanceFactor(request);
        var growthFactor = _options.GrowthFactors.GetGrowthFactor(baseInterval);
        var penaltyFactor = _options.OverduePenalties.GetPenaltyFactor(overdueDays);

        var enhancedInterval = (int)(baseInterval * growthFactor * performanceFactor * penaltyFactor);

        return Math.Clamp(enhancedInterval, 1, _options.MaxInterval);
    }

    /// <summary>
    /// 根據題型和表現計算表現係數
    /// </summary>
    private double GetPerformanceFactor(ReviewRequest request)
    {
        return request.QuestionType switch
        {
            "flip-memory" => GetFlipCardPerformanceFactor(request.ConfidenceLevel ?? 3),
            "vocab-choice" or "sentence-fill" or "sentence-reorder" => request.IsCorrect ? 1.1 : 0.6,
            "vocab-listening" or "sentence-listening" => request.IsCorrect ? 1.2 : 0.5, // 聽力題難度加權
            "sentence-speaking" => 1.0, // 口說題重在參與
            _ => 0.9
        };
    }

    /// <summary>
    /// 翻卡題信心等級映射
    /// </summary>
    private double GetFlipCardPerformanceFactor(int confidenceLevel)
    {
        return confidenceLevel switch
        {
            1 => 0.5,  // 很不確定
            2 => 0.7,  // 不確定
            3 => 0.9,  // 一般
            4 => 1.1,  // 確定
            5 => 1.4,  // 很確定
            _ => 0.9
        };
    }

    /// <summary>
    /// 從請求轉換為SM2Algorithm需要的品質分數
    /// </summary>
    private int GetQualityFromRequest(ReviewRequest request)
    {
        if (request.QuestionType == "flip-memory")
        {
            return request.ConfidenceLevel ?? 3;
        }

        return request.IsCorrect ? 4 : 2; // 客觀題簡化映射
    }

    /// <summary>
    /// 計算基礎熟悉度 (基於現有算法調整)
    /// </summary>
    private int CalculateMasteryLevel(int timesCorrect, int totalReviews, int currentInterval)
    {
        var successRate = totalReviews > 0 ? (double)timesCorrect / totalReviews : 0;

        var baseScore = Math.Min(timesCorrect * 8, 60);  // 答對次數貢獻 (最多60%)
        var intervalBonus = Math.Min(currentInterval / 365.0 * 25, 25); // 間隔貢獻 (最多25%)
        var accuracyBonus = successRate * 15; // 正確率貢獻 (最多15%)

        return Math.Min(100, (int)Math.Round(baseScore + intervalBonus + accuracyBonus));
    }
}