using Jiaowu.Api.Controllers;
using Jiaowu.Api.Domain.Academic;
using Jiaowu.Api.Domain.Identity;
using Jiaowu.Api.Infrastructure.Auth;
using Jiaowu.Api.Infrastructure.Caching;
using Jiaowu.Api.Infrastructure.Persistence;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace Jiaowu.Api.Tests;

public sealed class PersonnelControllerTests
{
    [Fact]
    public async Task ActivateTeacherAccount_CreatesAndLinksTeacherLogin()
    {
        await using var connection = new SqliteConnection("Data Source=:memory:");
        await connection.OpenAsync();
        var services = new ServiceCollection();
        services.AddLogging();
        services.AddDbContext<AppDbContext>(options => options.UseSqlite(connection));
        services
            .AddIdentityCore<ApplicationUser>(options =>
            {
                options.Password.RequiredLength = 8;
                options.Password.RequireDigit = true;
                options.Password.RequireLowercase = true;
                options.Password.RequireUppercase = true;
                options.Password.RequireNonAlphanumeric = true;
            })
            .AddRoles<ApplicationRole>()
            .AddEntityFrameworkStores<AppDbContext>();

        await using var provider = services.BuildServiceProvider();
        await using var scope = provider.CreateAsyncScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        await db.Database.EnsureCreatedAsync();
        var roleManager = scope.ServiceProvider
            .GetRequiredService<RoleManager<ApplicationRole>>();
        Assert.True((await roleManager.CreateAsync(new ApplicationRole
        {
            Name = SystemRoles.Teacher,
            Description = "教师"
        })).Succeeded);

        var college = new College { Code = "CS", Name = "计算机学院" };
        var teacher = new Teacher
        {
            TeacherNumber = "T2026999",
            Name = "测试教师",
            CollegeId = college.Id,
            Status = TeacherStatus.Active
        };
        db.AddRange(college, teacher);
        await db.SaveChangesAsync();

        var userManager = scope.ServiceProvider
            .GetRequiredService<UserManager<ApplicationUser>>();
        var controller = new PersonnelController(
            db,
            new TestDataScope(college.Id),
            userManager,
            NoOpAppCache.Instance);

        var result = await controller.ActivateTeacherAccount(
            teacher.Id,
            new TeacherAccountActivationRequest("Teacher@123"),
            CancellationToken.None);

        Assert.IsType<OkObjectResult>(result);
        var user = await userManager.FindByNameAsync(teacher.TeacherNumber);
        Assert.NotNull(user);
        Assert.Equal(teacher.Name, user.DisplayName);
        Assert.Equal(teacher.CollegeId, user.CollegeId);
        Assert.True(await userManager.IsInRoleAsync(user, SystemRoles.Teacher));
        db.ChangeTracker.Clear();
        var linkedTeacher = await db.Teachers.SingleAsync(x => x.Id == teacher.Id);
        Assert.Equal(user.Id, linkedTeacher.UserId);
    }

    private sealed class TestDataScope(Guid collegeId) : ICurrentUserDataScope
    {
        public CurrentUserScope Current { get; } = new(
            Guid.NewGuid(),
            "测试管理员",
            collegeId,
            DataScope.College,
            new HashSet<string>([SystemRoles.CollegeAdmin]));
    }
}
