using Jiaowu.Api.Domain.Academic;

namespace Jiaowu.Api.Infrastructure.Grades;

public static class GradeCalculator
{
    public static bool AreWeightsValid(
        decimal regularWeight,
        decimal finalWeight,
        IEnumerable<GradeItem> items) =>
        regularWeight is >= 0 and <= 100 &&
        finalWeight is >= 0 and <= 100 &&
        items.All(item => item.Weight is >= 0 and <= 100) &&
        regularWeight + finalWeight + items.Sum(item => item.Weight) == 100;

    public static decimal? CalculateTotal(
        decimal? regularScore,
        decimal? finalScore,
        IReadOnlyCollection<GradeItemScore> itemScores,
        decimal regularWeight,
        decimal finalWeight,
        IReadOnlyCollection<GradeItem> items,
        GradeExamStatus examStatus)
    {
        if (examStatus != GradeExamStatus.Normal && examStatus != GradeExamStatus.Makeup)
            return null;

        if (regularWeight > 0 && !regularScore.HasValue)
            return null;
        if (finalWeight > 0 && !finalScore.HasValue)
            return null;

        var itemWeightById = items.ToDictionary(item => item.Id, item => item.Weight);
        foreach (var itemScore in itemScores)
        {
            if (itemWeightById.TryGetValue(itemScore.GradeItemId, out var weight) &&
                weight > 0 && !itemScore.Score.HasValue)
                return null;
        }

        var total = (regularScore ?? 0) * regularWeight / 100;
        foreach (var itemScore in itemScores)
        {
            if (itemWeightById.TryGetValue(itemScore.GradeItemId, out var weight))
                total += (itemScore.Score ?? 0) * weight / 100;
        }
        total += (finalScore ?? 0) * finalWeight / 100;
        return Math.Round(total, 1, MidpointRounding.AwayFromZero);
    }

    public static decimal? CalculateGradePoint(decimal? totalScore)
    {
        if (!totalScore.HasValue) return null;
        return totalScore.Value switch
        {
            >= 90 => 4.0m,
            >= 85 => 3.7m,
            >= 82 => 3.3m,
            >= 78 => 3.0m,
            >= 75 => 2.7m,
            >= 72 => 2.3m,
            >= 68 => 2.0m,
            >= 64 => 1.5m,
            >= 60 => 1.0m,
            _ => 0m
        };
    }
}
