using Jiaowu.Api.Domain.Academic;
using Jiaowu.Api.Infrastructure.Persistence;
using Jiaowu.Api.Infrastructure.Scheduling;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace Jiaowu.Api.Tests;

public sealed class AutomaticScheduleJobProcessorTests
{
    [Fact]
    public async Task Processor_persists_progress_result_and_schedule_entries()
    {
        var databasePath = Path.Combine(
            Path.GetTempPath(),
            $"jiaowu-auto-schedule-{Guid.NewGuid():N}.sqlite");
        var services = new ServiceCollection();
        services.AddLogging();
        services.AddDbContext<AppDbContext>(
            options => options.UseSqlite(
                $"Data Source={databasePath};Pooling=False"));
        services.AddScoped<AutomaticScheduleGenerator>();
        services.AddScoped<AutomaticScheduleJobProcessor>();
        var provider = services.BuildServiceProvider();

        try
        {
            Guid jobId;
            await using (var seedScope = provider.CreateAsyncScope())
            {
                var db = seedScope.ServiceProvider.GetRequiredService<AppDbContext>();
                await db.Database.EnsureCreatedAsync();
                var term = new AcademicTerm
                {
                    Code = "2026-JOB",
                    Name = "后台排课学期",
                    AcademicYear = "2026-2027",
                    Season = TermSeason.Autumn,
                    StartDate = new DateOnly(2026, 9, 1),
                    EndDate = new DateOnly(2027, 1, 15)
                };
                var college = new College { Code = "JOB", Name = "后台任务学院" };
                var course = new Course
                {
                    Code = "JOB-01",
                    Name = "后台任务课程",
                    College = college,
                    Credits = 1,
                    TotalHours = 32,
                    LectureHours = 32
                };
                var task = new TeachingTask
                {
                    TaskNumber = "TASK-JOB",
                    Name = "后台任务教学班",
                    AcademicTerm = term,
                    Course = course,
                    Capacity = 100,
                    StartWeek = 1,
                    EndWeek = 16,
                    WeeklyHours = 2,
                    Status = TeachingTaskStatus.Published
                };
                var plan = new SchedulePlan
                {
                    AcademicTerm = term,
                    Name = "后台排课草稿",
                    Version = "V1"
                };
                var job = new AutomaticScheduleJob
                {
                    SchedulePlan = plan,
                    ActiveSchedulePlanId = plan.Id
                };
                jobId = job.Id;
                db.AddRange(term, college, course, task, plan, job);
                db.ScheduleTimeSlots.AddRange(
                    new ScheduleTimeSlot
                    {
                        AcademicTerm = term,
                        PeriodNumber = 1,
                        Name = "第 1 节",
                        StartsAt = new TimeOnly(8, 0),
                        EndsAt = new TimeOnly(8, 45)
                    },
                    new ScheduleTimeSlot
                    {
                        AcademicTerm = term,
                        PeriodNumber = 2,
                        Name = "第 2 节",
                        StartsAt = new TimeOnly(8, 55),
                        EndsAt = new TimeOnly(9, 40)
                    });
                db.TeachingTaskScheduleConstraints.Add(
                    new TeachingTaskScheduleConstraint
                    {
                        TeachingTask = task,
                        RequiresClassroom = false,
                        AllowedDayOfWeeks = "2",
                        EarliestPeriod = 1,
                        LatestPeriod = 2
                    });
                await db.SaveChangesAsync();
            }

            await using (var workerScope = provider.CreateAsyncScope())
            {
                var processor = workerScope.ServiceProvider
                    .GetRequiredService<AutomaticScheduleJobProcessor>();
                await processor.ProcessAsync(jobId, CancellationToken.None);
            }

            await using (var assertScope = provider.CreateAsyncScope())
            {
                var db = assertScope.ServiceProvider.GetRequiredService<AppDbContext>();
                var job = await db.AutomaticScheduleJobs.SingleAsync();
                var entry = await db.ScheduleEntries.SingleAsync();

                Assert.Equal(AutomaticScheduleJobStatus.Succeeded, job.Status);
                Assert.Null(job.ActiveSchedulePlanId);
                Assert.Equal(1, job.TotalTasks);
                Assert.Equal(1, job.ProcessedTasks);
                Assert.Equal(1, job.CreatedEntries);
                Assert.Equal(1, job.CompletedTasks);
                Assert.Equal("[]", job.MessagesJson);
                Assert.NotNull(job.StartedAt);
                Assert.NotNull(job.CompletedAt);
                Assert.Null(job.ErrorMessage);
                Assert.Equal(2, entry.DayOfWeek);
                Assert.Equal(2, entry.PeriodCount);
            }
        }
        finally
        {
            await provider.DisposeAsync();
            File.Delete(databasePath);
        }
    }
}
