using ClaudeDo.Data;
using ClaudeDo.Data.Models;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Hub;
using ClaudeDo.Worker.Tests.Infrastructure;
using Xunit;

namespace ClaudeDo.Worker.Tests.Hub;

/// UpdateListConfig's "all fields blank -> delete the row" branch used to delete unconditionally,
/// silently dropping fields the caller doesn't own. It may only delete when nothing else is stored;
/// the preserve-the-stored-value side is covered by ListConfigTicketProjectTests.
public sealed class ListConfigHubTests : IDisposable
{
    private readonly DbFixture _db = new();

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

    private WorkerHub CreateHub()
    {
        var factory = _db.CreateFactory();
        var broadcaster = new HubBroadcaster(new CapturingHubContext());
        var hub = new WorkerHub(
            null!, null!, null!, null!, broadcaster, factory,
            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;
    }

    // Each helper opens (and disposes) its own short-lived context/repository -- ListRepository's
    // GetConfigAsync doesn't AsNoTracking(), so reusing one long-lived instance across a hub call
    // that writes via a *different* context would return a stale, identity-mapped entity.

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

    private async Task SeedConfigAsync(string listId, string? model = null)
    {
        await using var ctx = _db.CreateContext();
        await new ListRepository(ctx).SetConfigAsync(new ListConfigEntity { ListId = listId, Model = model });
    }

    private async Task<ListConfigEntity?> GetConfigAsync(string listId)
    {
        await using var ctx = _db.CreateContext();
        return await new ListRepository(ctx).GetConfigAsync(listId);
    }

    [Fact]
    public async Task UpdateListConfig_AllBlank_NoUnrelatedSettings_DeletesRow()
    {
        var hub = CreateHub();
        var listId = await SeedListAsync();
        await SeedConfigAsync(listId, model: "opus");

        await hub.UpdateListConfig(new UpdateListConfigDto(listId, null, null, null));

        Assert.Null(await GetConfigAsync(listId));
    }
}
