using System.Security.Claims;
using Jiaowu.Api.Domain.Academic;
using Jiaowu.Api.Domain.Identity;
using Jiaowu.Api.Infrastructure.Auth;
using Microsoft.AspNetCore.Http;

namespace Jiaowu.Api.Tests;

public sealed class DataScopeTests
{
    [Theory]
    [InlineData(SystemRoles.Student, null, DataScope.Self)]
    [InlineData(SystemRoles.Counselor, SystemRoles.Teacher, DataScope.Class)]
    [InlineData(SystemRoles.CollegeAdmin, SystemRoles.Counselor, DataScope.College)]
    [InlineData(SystemRoles.SuperAdmin, SystemRoles.CollegeAdmin, DataScope.All)]
    [InlineData(SystemRoles.AcademicAdmin, SystemRoles.Student, DataScope.All)]
    public void Resolver_UsesHighestScope(
        string firstRole,
        string? secondRole,
        DataScope expected)
    {
        var roles = secondRole is null
            ? [firstRole]
            : new[] { firstRole, secondRole };

        Assert.Equal(expected, EffectiveDataScopeResolver.Resolve(roles));
    }

    [Fact]
    public void CurrentScope_ReadsIdentityAndCollegeClaims()
    {
        var userId = Guid.NewGuid();
        var collegeId = Guid.NewGuid();
        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
            new Claim(ClaimTypes.Name, "院系管理员"),
            new Claim(ClaimTypes.Role, SystemRoles.CollegeAdmin),
            new Claim("college_id", collegeId.ToString())
        };
        var accessor = new HttpContextAccessor
        {
            HttpContext = new DefaultHttpContext
            {
                User = new ClaimsPrincipal(new ClaimsIdentity(claims, "test"))
            }
        };

        var current = new CurrentUserDataScope(accessor).Current;

        Assert.Equal(userId, current.UserId);
        Assert.Equal(collegeId, current.CollegeId);
        Assert.Equal(DataScope.College, current.Scope);
        Assert.True(current.CanAccessCollege(collegeId));
        Assert.False(current.CanAccessCollege(Guid.NewGuid()));
    }

    [Theory]
    [InlineData(CourseNature.MajorRequired, true)]
    [InlineData(CourseNature.MajorElective, true)]
    [InlineData(CourseNature.Practice, true)]
    [InlineData(CourseNature.GeneralRequired, false)]
    [InlineData(CourseNature.GeneralElective, false)]
    public void CollegeAdmin_OnlyMaintainsDelegatedCourseNatures(
        CourseNature nature,
        bool expected)
    {
        var collegeId = Guid.NewGuid();
        var scope = new CurrentUserScope(
            Guid.NewGuid(),
            "学院教务",
            collegeId,
            DataScope.College,
            new HashSet<string>([SystemRoles.CollegeAdmin]));

        Assert.Equal(
            expected,
            CourseMaintenancePolicy.CanManage(scope, collegeId, nature));
        Assert.False(CourseMaintenancePolicy.CanManage(
            scope,
            Guid.NewGuid(),
            nature));
    }

    [Theory]
    [InlineData(SystemRoles.SuperAdmin)]
    [InlineData(SystemRoles.AcademicAdmin)]
    public void SchoolAdministrators_RetainWholeCourseCatalogueManagement(string role)
    {
        var scope = new CurrentUserScope(
            Guid.NewGuid(),
            "校级教务",
            null,
            DataScope.All,
            new HashSet<string>([role]));

        Assert.True(CourseMaintenancePolicy.CanManage(
            scope,
            Guid.NewGuid(),
            CourseNature.GeneralRequired));
    }

    [Theory]
    [InlineData(CourseNature.MajorRequired, true)]
    [InlineData(CourseNature.MajorElective, true)]
    [InlineData(CourseNature.Practice, true)]
    [InlineData(CourseNature.GeneralRequired, false)]
    [InlineData(CourseNature.GeneralElective, false)]
    public void CollegeAdmin_Manages_Own_Professional_TeachingTasks(
        CourseNature nature,
        bool expected)
    {
        var collegeId = Guid.NewGuid();
        var scope = new CurrentUserScope(
            Guid.NewGuid(),
            "学院教务",
            collegeId,
            DataScope.College,
            new HashSet<string>([SystemRoles.CollegeAdmin]));

        Assert.Equal(
            expected,
            TeachingTaskMaintenancePolicy.CanManage(scope, collegeId, nature));
        Assert.False(TeachingTaskMaintenancePolicy.CanManage(
            scope,
            Guid.NewGuid(),
            nature));
    }

    [Theory]
    [InlineData(CourseNature.GeneralRequired, true)]
    [InlineData(CourseNature.GeneralElective, true)]
    [InlineData(CourseNature.MajorRequired, false)]
    [InlineData(CourseNature.MajorElective, false)]
    [InlineData(CourseNature.Practice, false)]
    public void AcademicAdmin_Manages_Public_Not_Professional_TeachingTasks(
        CourseNature nature,
        bool expected)
    {
        var scope = new CurrentUserScope(
            Guid.NewGuid(),
            "校级教务",
            null,
            DataScope.All,
            new HashSet<string>([SystemRoles.AcademicAdmin]));

        Assert.Equal(
            expected,
            TeachingTaskMaintenancePolicy.CanManage(
                scope,
                Guid.NewGuid(),
                nature));
    }

    [Theory]
    [InlineData(CourseNature.GeneralRequired)]
    [InlineData(CourseNature.MajorRequired)]
    [InlineData(CourseNature.Practice)]
    public void SuperAdmin_Can_Override_TeachingTask_Responsibility(
        CourseNature nature)
    {
        var scope = new CurrentUserScope(
            Guid.NewGuid(),
            "超级管理员",
            null,
            DataScope.All,
            new HashSet<string>([SystemRoles.SuperAdmin]));

        Assert.True(TeachingTaskMaintenancePolicy.CanManage(
            scope,
            Guid.NewGuid(),
            nature));
    }

    [Fact]
    public void Combined_School_And_College_Roles_Keep_Both_Responsibilities()
    {
        var collegeId = Guid.NewGuid();
        var scope = new CurrentUserScope(
            Guid.NewGuid(),
            "校院兼岗教务",
            collegeId,
            DataScope.All,
            new HashSet<string>(
                [SystemRoles.AcademicAdmin, SystemRoles.CollegeAdmin]));

        Assert.True(TeachingTaskMaintenancePolicy.CanManage(
            scope,
            Guid.NewGuid(),
            CourseNature.GeneralRequired));
        Assert.True(TeachingTaskMaintenancePolicy.CanManage(
            scope,
            collegeId,
            CourseNature.MajorRequired));
        Assert.False(TeachingTaskMaintenancePolicy.CanManage(
            scope,
            Guid.NewGuid(),
            CourseNature.MajorRequired));
    }
}
