using ClaudeDo.Data.Models;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Hub;
using ClaudeDo.Worker.Tests.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Xunit;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;

namespace ClaudeDo.Worker.Tests.Hub;

public sealed class ClearMyDayHubTests : IDisposable
{
    private readonly DbFixture _db = new();

    public void Dispose() => _db.Dispose();

    private WorkerHub CreateHub()
    {
        var broadcaster = new HubBroadcaster(new CapturingHubContext());
        var hub = new WorkerHub(
            null!, null!, null!, null!, broadcaster, _db.CreateFactory(),
            null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!, null!,
            null!, new ClaudeDo.Worker.Online.OnlineInboxConfig(), new ClaudeDo.Worker.OnlineRefreshTokenStore(new ClaudeDo.Worker.DpapiTokenStore("unused.token")),
            new ClaudeDo.Worker.Runner.PendingQuestionRegistry(), null!);
        hub.Clients = new FakeHubCallerClients(new RecordingClientProxy());
        hub.Context = new FakeHubCallerContext();
        return hub;
    }

    private async Task<(string listId, string idleMyDay, string doneMyDay, string notMyDay)> SeedAsync()
    {
        using var ctx = _db.CreateContext();
        var listId = Guid.NewGuid().ToString();
        await new ListRepository(ctx).AddAsync(new ListEntity
        {
            Id = listId, Name = "L", CreatedAt = DateTime.UtcNow,
        });

        var repo = new TaskRepository(ctx);

        var idleMyDay = Guid.NewGuid().ToString();
        await repo.AddAsync(new TaskEntity
        {
            Id = idleMyDay, ListId = listId, Title = "Idle MyDay",
            Status = TaskStatus.Idle, IsMyDay = true,
            CreatedAt = DateTime.UtcNow, CommitType = "feat",
        });

        var doneMyDay = Guid.NewGuid().ToString();
        await repo.AddAsync(new TaskEntity
        {
            Id = doneMyDay, ListId = listId, Title = "Done MyDay",
            Status = TaskStatus.Done, IsMyDay = true,
            CreatedAt = DateTime.UtcNow, CommitType = "feat",
        });

        var notMyDay = Guid.NewGuid().ToString();
        await repo.AddAsync(new TaskEntity
        {
            Id = notMyDay, ListId = listId, Title = "Not MyDay",
            Status = TaskStatus.Idle, IsMyDay = false,
            CreatedAt = DateTime.UtcNow, CommitType = "feat",
        });

        return (listId, idleMyDay, doneMyDay, notMyDay);
    }

    [Fact]
    public async Task ClearMyDay_clears_all_isMyDay_tasks()
    {
        var (_, _, _, notMyDay) = await SeedAsync();
        var hub = CreateHub();

        var cleared = await hub.ClearMyDay();

        Assert.Equal(2, cleared);

        await using var ctx = _db.CreateContext();
        Assert.False(await ctx.Tasks.AnyAsync(t => t.IsMyDay));

        var notMyDayTask = await ctx.Tasks.FindAsync(notMyDay);
        Assert.NotNull(notMyDayTask);
        Assert.False(notMyDayTask!.IsMyDay);
    }

    [Fact]
    public async Task ClearMyDay_returns_zero_when_no_myDay_tasks()
    {
        using var ctx = _db.CreateContext();
        var listId = Guid.NewGuid().ToString();
        await new ListRepository(ctx).AddAsync(new ListEntity
        {
            Id = listId, Name = "L2", CreatedAt = DateTime.UtcNow,
        });
        await new TaskRepository(ctx).AddAsync(new TaskEntity
        {
            Id = Guid.NewGuid().ToString(), ListId = listId, Title = "No MyDay",
            Status = TaskStatus.Idle, IsMyDay = false,
            CreatedAt = DateTime.UtcNow, CommitType = "feat",
        });

        var hub = CreateHub();
        var cleared = await hub.ClearMyDay();

        Assert.Equal(0, cleared);
    }
}
