using Jiaowu.Api.Domain.Academic;
using Jiaowu.Api.Infrastructure.Graduation;

namespace Jiaowu.Api.Tests;

public sealed class GraduationAuditRulesTests
{
    [Fact]
    public void Curriculum_groups_Accept_Any_Options_That_Fulfill_Required_Credits()
    {
        var football = new Course { Code = "PE101", Name = "足球", Credits = 1 };
        var basketball = new Course { Code = "PE102", Name = "篮球", Credits = 1 };
        var swimming = new Course { Code = "PE103", Name = "游泳", Credits = 1 };
        var module = new CurriculumModule
        {
            Code = "SPORTS",
            Name = "大学体育",
            RequiredCredits = 2,
            Courses = [Option(football), Option(basketball), Option(swimming)]
        };

        var completed = CurriculumCompletionRules.Evaluate(
            [module],
            new HashSet<Guid>([football.Id, swimming.Id]));
        var incomplete = CurriculumCompletionRules.Evaluate(
            [module],
            new HashSet<Guid>([football.Id]));

        Assert.Equal(1, completed.RequirementCount);
        Assert.Equal(1, completed.PassedRequirementCount);
        Assert.Empty(completed.MissingRequirements);
        Assert.Equal(0, incomplete.PassedRequirementCount);
        Assert.Contains("大学体育（还差 1 学分）", incomplete.MissingRequirements);
    }

    [Fact]
    public void Curriculum_groups_Still_Require_Every_Fixed_Course()
    {
        var ideology = new Course { Code = "MORAL101", Name = "思想道德与法治", Credits = 3 };
        var module = new CurriculumModule
        {
            Code = "MORAL",
            Name = "德育课程",
            RequiredCredits = 3,
            Courses =
            [
                new CurriculumCourse
                {
                    CourseId = ideology.Id,
                    Course = ideology,
                    Type = CurriculumCourseType.Required
                }
            ]
        };

        var result = CurriculumCompletionRules.Evaluate([module], new HashSet<Guid>());

        Assert.Equal(1, result.RequirementCount);
        Assert.Equal(0, result.PassedRequirementCount);
        Assert.Contains("思想道德与法治", result.MissingRequirements);
    }

    [Fact]
    public void Active_student_with_full_credits_and_courses_is_eligible()
    {
        var conclusion = GraduationAuditRules.Evaluate(
            true, StudentStatus.Active, 160, 162, 42, 42, 0);

        Assert.Equal(GraduationAuditConclusion.Eligible, conclusion);
    }

    [Theory]
    [InlineData(false, StudentStatus.Active, 160, 162, 42, 42, 0)]
    [InlineData(true, StudentStatus.Suspended, 160, 162, 42, 42, 0)]
    [InlineData(true, StudentStatus.Active, 160, 159, 42, 42, 0)]
    [InlineData(true, StudentStatus.Active, 160, 162, 42, 41, 0)]
    [InlineData(true, StudentStatus.Active, 160, 162, 42, 42, 1)]
    public void Any_unresolved_requirement_makes_student_ineligible(
        bool hasPlan,
        StudentStatus status,
        decimal requiredCredits,
        decimal earnedCredits,
        int requiredCourses,
        int passedRequiredCourses,
        int failedCourses)
    {
        var conclusion = GraduationAuditRules.Evaluate(
            hasPlan, status, requiredCredits, earnedCredits,
            requiredCourses, passedRequiredCourses, failedCourses);

        Assert.Equal(GraduationAuditConclusion.Ineligible, conclusion);
    }

    private static CurriculumCourse Option(Course course) =>
        new()
        {
            CourseId = course.Id,
            Course = course,
            Type = CurriculumCourseType.Elective
        };
}
