namespace DramaLing.Api.Services;

public record SM2Input(
    int Quality,            // 1-5 評分
    float EasinessFactor,   // 難度係數
    int Repetitions,        // 重複次數
    int IntervalDays        // 當前間隔天數
);

public record SM2Result(
    float EasinessFactor,   // 新的難度係數
    int Repetitions,        // 新的重複次數
    int IntervalDays,       // 新的間隔天數
    DateTime NextReviewDate // 下次複習日期
);

public static class SM2Algorithm
{
    // SM-2 算法常數
    private const float MIN_EASINESS_FACTOR = 1.3f;
    private const float MAX_EASINESS_FACTOR = 2.5f;
    private const float INITIAL_EASINESS_FACTOR = 2.5f;
    private const int MIN_INTERVAL = 1;
    private const int MAX_INTERVAL = 365;

    /// <summary>
    /// 計算下次複習的間隔和參數
    /// </summary>
    public static SM2Result Calculate(SM2Input input)
    {
        var (quality, easinessFactor, repetitions, intervalDays) = input;

        // 驗證輸入參數
        if (quality < 1 || quality > 5)
            throw new ArgumentException("Quality must be between 1 and 5", nameof(input));

        // 更新難度係數
        var newEasinessFactor = UpdateEasinessFactor(easinessFactor, quality);

        int newRepetitions;
        int newIntervalDays;

        // 如果回答錯誤 (quality < 3)，重置進度
        if (quality < 3)
        {
            newRepetitions = 0;
            newIntervalDays = 1;
        }
        else
        {
            // 如果回答正確，增加重複次數並計算新間隔
            newRepetitions = repetitions + 1;

            newIntervalDays = newRepetitions switch
            {
                1 => 1,
                2 => 6,
                _ => (int)Math.Round(intervalDays * newEasinessFactor)
            };
        }

        // 限制間隔範圍
        newIntervalDays = Math.Clamp(newIntervalDays, MIN_INTERVAL, MAX_INTERVAL);

        // 計算下次複習日期
        var nextReviewDate = DateTime.Today.AddDays(newIntervalDays);

        return new SM2Result(
            newEasinessFactor,
            newRepetitions,
            newIntervalDays,
            nextReviewDate
        );
    }

    /// <summary>
    /// 更新難度係數
    /// </summary>
    private static float UpdateEasinessFactor(float currentEF, int quality)
    {
        // SM-2 公式：EF' = EF + (0.1 - (5-q) * (0.08 + (5-q) * 0.02))
        var newEF = currentEF + (0.1f - (5 - quality) * (0.08f + (5 - quality) * 0.02f));

        // 限制在有效範圍內
        return Math.Clamp(newEF, MIN_EASINESS_FACTOR, MAX_EASINESS_FACTOR);
    }

    /// <summary>
    /// 獲取初始參數（新詞卡）
    /// </summary>
    public static SM2Input GetInitialParameters()
    {
        return new SM2Input(
            Quality: 3,
            EasinessFactor: INITIAL_EASINESS_FACTOR,
            Repetitions: 0,
            IntervalDays: 1
        );
    }

    /// <summary>
    /// 根據評分獲取描述
    /// </summary>
    public static string GetQualityDescription(int quality)
    {
        return quality switch
        {
            1 => "完全不記得",
            2 => "有印象但錯誤",
            3 => "困難但正確",
            4 => "猶豫後正確",
            5 => "輕鬆正確",
            _ => "無效評分"
        };
    }

    /// <summary>
    /// 計算掌握度百分比
    /// </summary>
    public static int CalculateMastery(int repetitions, float easinessFactor)
    {
        // 基於重複次數和難度係數計算掌握度 (0-100)
        var baseScore = Math.Min(repetitions * 20, 80); // 重複次數最多貢獻80分
        var efficiencyBonus = Math.Min((easinessFactor - 1.3f) * 16.67f, 20f); // 難度係數最多貢獻20分

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

/// <summary>
/// 複習優先級計算器
/// </summary>
public static class ReviewPriorityCalculator
{
    /// <summary>
    /// 計算複習優先級 (數字越大優先級越高)
    /// </summary>
    public static double CalculatePriority(DateTime nextReviewDate, float easinessFactor, int repetitions)
    {
        var now = DateTime.Today;
        var daysDiff = (now - nextReviewDate).Days;

        // 過期天數的權重 (越過期優先級越高)
        var overdueWeight = Math.Max(0, daysDiff) * 10;

        // 難度權重 (越難的優先級越高)
        var difficultyWeight = (3.8f - easinessFactor) * 5;

        // 新詞權重 (新詞優先級較高)
        var newWordWeight = repetitions == 0 ? 20 : 0;

        return overdueWeight + difficultyWeight + newWordWeight;
    }

    /// <summary>
    /// 獲取應該複習的詞卡
    /// </summary>
    public static bool ShouldReview(DateTime nextReviewDate)
    {
        return DateTime.Today >= nextReviewDate;
    }
}