using Jiaowu.Api.Domain.Academic;

namespace Jiaowu.Api.Infrastructure.Graduation;

public sealed record CurriculumCompletionSummary(
    int RequirementCount,
    int PassedRequirementCount,
    IReadOnlyList<string> MissingRequirements);

public static class CurriculumCompletionRules
{
    public static CurriculumCompletionSummary Evaluate(
        IEnumerable<CurriculumModule> modules,
        IReadOnlySet<Guid> passedCourseIds)
    {
        var moduleList = modules.ToList();
        var requiredCourses = moduleList
            .SelectMany(x => x.Courses)
            .Where(x => x.Type == CurriculumCourseType.Required)
            .ToList();
        var optionGroups = moduleList
            .Where(x =>
                x.RequiredCredits > 0 &&
                x.Courses.Any(course => course.Type == CurriculumCourseType.Elective))
            .ToList();

        var missing = requiredCourses
            .Where(x => !passedCourseIds.Contains(x.CourseId))
            .Select(x => x.Course?.Name ?? "未命名必修课程")
            .Distinct()
            .ToList();
        var passedRequiredCourses = requiredCourses.Count -
                                    requiredCourses.Count(x =>
                                        !passedCourseIds.Contains(x.CourseId));
        var passedGroups = 0;
        foreach (var module in optionGroups)
        {
            var earnedGroupCredits = module.Courses
                .Where(x => passedCourseIds.Contains(x.CourseId))
                .GroupBy(x => x.CourseId)
                .Sum(group => group.Max(x => x.Course?.Credits ?? 0));
            if (earnedGroupCredits >= module.RequiredCredits)
            {
                passedGroups++;
                continue;
            }

            var shortage = module.RequiredCredits - earnedGroupCredits;
            missing.Add($"{module.Name}（还差 {shortage:0.#} 学分）");
        }

        return new CurriculumCompletionSummary(
            requiredCourses.Count + optionGroups.Count,
            passedRequiredCourses + passedGroups,
            missing);
    }
}
