using System.Text.Json;
using Jiaowu.Api.Controllers;
using Jiaowu.Api.Domain.Academic;
using Jiaowu.Api.Domain.Identity;
using Jiaowu.Api.Infrastructure.Auth;
using Jiaowu.Api.Infrastructure.Persistence;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;

namespace Jiaowu.Api.Tests;

public sealed class GraduationAuditsControllerTests
{
    [Fact]
    public async Task GetBatch_ReturnsPagedResultsAndWholeBatchSummary()
    {
        await using var connection = new SqliteConnection("Data Source=:memory:");
        await connection.OpenAsync();
        var options = new DbContextOptionsBuilder<AppDbContext>()
            .UseSqlite(connection)
            .Options;
        await using var db = new AppDbContext(options);
        await db.Database.EnsureCreatedAsync();

        var college = new College { Code = "CS", Name = "计算机学院" };
        var major = new Major
        {
            Code = "SE",
            Name = "软件工程",
            CollegeId = college.Id,
            DegreeType = "工学"
        };
        var administrativeClass = new AdministrativeClass
        {
            Code = "SE2601",
            Name = "软件工程2601班",
            MajorId = major.Id,
            Grade = 2026
        };
        var batch = new GraduationAuditBatch
        {
            Name = "2030届毕业资格审核",
            GraduationYear = 2030,
            EnrollmentYear = 2026
        };
        db.AddRange(college, major, administrativeClass, batch);

        for (var index = 1; index <= 25; index++)
        {
            var student = new Student
            {
                StudentNumber = $"2026{index:0000}",
                Name = index == 17 ? "分页检索学生" : $"学生{index:00}",
                AdministrativeClassId = administrativeClass.Id,
                EnrollmentYear = 2026,
                EnrollmentDate = new DateOnly(2026, 9, 1)
            };
            db.Students.Add(student);
            db.GraduationAuditResults.Add(new GraduationAuditResult
            {
                GraduationAuditBatchId = batch.Id,
                StudentId = student.Id,
                StudentStatusSnapshot = StudentStatus.Active,
                RequiredCredits = 160,
                EarnedCredits = 150,
                RequiredCourseCount = 40,
                PassedRequiredCourseCount = 38,
                FailedCourseCount = 1,
                MissingCourseNames = "毕业设计",
                CalculatedConclusion = index % 2 == 0
                    ? GraduationAuditConclusion.Eligible
                    : GraduationAuditConclusion.Ineligible,
                Conclusion = index % 2 == 0
                    ? GraduationAuditConclusion.Eligible
                    : GraduationAuditConclusion.Ineligible,
                IsOverridden = index == 1
            });
        }
        await db.SaveChangesAsync();

        var controller = new GraduationAuditsController(db, new AllDataScope());
        var pageResult = Assert.IsType<OkObjectResult>(await controller.GetBatch(
            batch.Id,
            page: 2,
            pageSize: 10));
        using var pageJson = ToJson(pageResult.Value);

        Assert.Equal(25, pageJson.RootElement.GetProperty("resultCount").GetInt32());
        Assert.Equal(12, pageJson.RootElement.GetProperty("eligibleCount").GetInt32());
        Assert.Equal(13, pageJson.RootElement.GetProperty("ineligibleCount").GetInt32());
        Assert.Equal(1, pageJson.RootElement.GetProperty("overrideCount").GetInt32());
        var pagedResults = pageJson.RootElement.GetProperty("results");
        Assert.Equal(25, pagedResults.GetProperty("total").GetInt32());
        Assert.Equal(2, pagedResults.GetProperty("page").GetInt32());
        Assert.Equal(10, pagedResults.GetProperty("items").GetArrayLength());

        var filteredResult = Assert.IsType<OkObjectResult>(await controller.GetBatch(
            batch.Id,
            keyword: "分页检索",
            conclusion: GraduationAuditConclusion.Ineligible));
        using var filteredJson = ToJson(filteredResult.Value);
        var filteredResults = filteredJson.RootElement.GetProperty("results");
        Assert.Equal(1, filteredResults.GetProperty("total").GetInt32());
        Assert.Equal(
            "分页检索学生",
            filteredResults.GetProperty("items")[0].GetProperty("name").GetString());
    }

    private static JsonDocument ToJson(object? value) => JsonDocument.Parse(
        JsonSerializer.Serialize(value, new JsonSerializerOptions(JsonSerializerDefaults.Web)));

    private sealed class AllDataScope : ICurrentUserDataScope
    {
        public CurrentUserScope Current { get; } = new(
            Guid.NewGuid(),
            "校级教务",
            null,
            DataScope.All,
            new HashSet<string>([SystemRoles.AcademicAdmin]));
    }
}
