using ClaudeDo.Data;
using ClaudeDo.Data.Models;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Hub;
using ClaudeDo.Worker.Lifecycle;
using ClaudeDo.Worker.Tests.Infrastructure;
using Microsoft.Extensions.Logging.Abstractions;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;

namespace ClaudeDo.Worker.Tests.Services;

public sealed class StaleTaskRecoveryTests : IDisposable
{
    private readonly DbFixture _db = new();
    private readonly ClaudeDoDbContext _ctx;
    private readonly TaskRepository _tasks;
    private readonly ListRepository _lists;

    public StaleTaskRecoveryTests()
    {
        _ctx = _db.CreateContext();
        _tasks = new TaskRepository(_ctx);
        _lists = new ListRepository(_ctx);
    }

    public void Dispose()
    {
        _ctx.Dispose();
        _db.Dispose();
    }

    [Fact]
    public async Task StartAsync_Flips_Running_Tasks_To_Failed()
    {
        var listId = Guid.NewGuid().ToString();
        await _lists.AddAsync(new ListEntity { Id = listId, Name = "Test", CreatedAt = DateTime.UtcNow });

        var running = new TaskEntity
        {
            Id = Guid.NewGuid().ToString(),
            ListId = listId,
            Title = "Running task",
            Status = TaskStatus.Running,
            CreatedAt = DateTime.UtcNow,
        };
        var queued = new TaskEntity
        {
            Id = Guid.NewGuid().ToString(),
            ListId = listId,
            Title = "Queued task",
            Status = TaskStatus.Queued,
            CreatedAt = DateTime.UtcNow,
        };

        await _tasks.AddAsync(running);
        await _tasks.AddAsync(queued);

        var built = TaskStateServiceBuilder.Build(_db.CreateFactory());
        var hubContext = new CapturingHubContext();
        var recovery = new StaleTaskRecovery(built.State, new HubBroadcaster(hubContext), NullLogger<StaleTaskRecovery>.Instance);
        await recovery.StartAsync(CancellationToken.None);

        var r = await _tasks.GetByIdAsync(running.Id);
        Assert.Equal(TaskStatus.Failed, r!.Status);
        Assert.StartsWith("[stale] ", r.Result);

        var q = await _tasks.GetByIdAsync(queued.Id);
        Assert.Equal(TaskStatus.Queued, q!.Status);

        Assert.Contains(hubContext.Proxy.Calls, c =>
            c.Method == "OperationProgress" && (string)c.Args[0]! == "startup-recovery");
    }
}
