using ClaudeDo.Data;
using ClaudeDo.Data.Models;
using ClaudeDo.Ui.ViewModels.Islands;
using Microsoft.EntityFrameworkCore;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;

namespace ClaudeDo.Ui.Tests.ViewModels;

// The hub's QueuePlanningSubtasksAsync queues every Idle child of a finalized planning parent
// unconditionally — it has no notion of a UI-hosted ConPTY session. SendToQueueAsync must block
// the whole plan when any child has an open interactive session, otherwise that child's worktree
// gets an autonomous run racing the user's own hand-driven edits.
public class TasksIslandQueuePlanInteractiveGateTests : IDisposable
{
    private readonly string _dbPath;

    public TasksIslandQueuePlanInteractiveGateTests()
    {
        _dbPath = Path.Combine(Path.GetTempPath(), $"claudedo_queueplan_gate_{Guid.NewGuid():N}.db");
        using var ctx = NewContext();
        ctx.Database.EnsureCreated();
    }

    public void Dispose()
    {
        try { File.Delete(_dbPath); } catch { }
        try { File.Delete(_dbPath + "-wal"); } catch { }
        try { File.Delete(_dbPath + "-shm"); } catch { }
    }

    private ClaudeDoDbContext NewContext()
    {
        var opts = new DbContextOptionsBuilder<ClaudeDoDbContext>()
            .UseSqlite($"Data Source={_dbPath}")
            .Options;
        return new ClaudeDoDbContext(opts);
    }


    private sealed class RecordingWorkerClient : StubWorkerClient
    {
        public override bool IsConnected => true;
        public string? QueuedParentId;
        public override Task QueuePlanningSubtasksAsync(string parentTaskId, CancellationToken ct = default)
        {
            QueuedParentId = parentTaskId;
            return Task.CompletedTask;
        }
    }

    private TasksIslandViewModel BuildViewModel(StubWorkerClient worker) =>
        new(new TestDbFactory(NewContext), worker);

    [Fact]
    public async Task SendToQueue_FinalizedPlan_BlockedWhenAChildHasInteractiveSession()
    {
        var worker = new RecordingWorkerClient();
        var vm = BuildViewModel(worker);

        var parent = new TaskRowViewModel
        {
            Id = "parent-1",
            Status = TaskStatus.Idle,
            PlanningPhase = PlanningPhase.Finalized,
            HasPlanningChildren = true,
        };
        var interactiveChild = new TaskRowViewModel
        {
            Id = "child-1",
            Title = "Fix the flaky test",
            ParentTaskId = "parent-1",
            Status = TaskStatus.Idle,
            HasInteractiveSession = true,
        };
        var otherChild = new TaskRowViewModel
        {
            Id = "child-2",
            ParentTaskId = "parent-1",
            Status = TaskStatus.Idle,
        };
        vm.Items.Add(parent);
        vm.Items.Add(interactiveChild);
        vm.Items.Add(otherChild);

        Assert.True(parent.CanQueuePlan);

        string? reportedError = null;
        vm.ErrorReported += msg => reportedError = msg;

        await vm.SendToQueueCommand.ExecuteAsync(parent);

        Assert.Null(worker.QueuedParentId);
        Assert.NotNull(reportedError);
        Assert.Contains("Fix the flaky test", reportedError);
    }

    [Fact]
    public async Task SendToQueue_FinalizedPlan_ProceedsWhenNoChildHasInteractiveSession()
    {
        var worker = new RecordingWorkerClient();
        var vm = BuildViewModel(worker);

        var parent = new TaskRowViewModel
        {
            Id = "parent-2",
            Status = TaskStatus.Idle,
            PlanningPhase = PlanningPhase.Finalized,
            HasPlanningChildren = true,
        };
        var child = new TaskRowViewModel
        {
            Id = "child-3",
            ParentTaskId = "parent-2",
            Status = TaskStatus.Idle,
        };
        vm.Items.Add(parent);
        vm.Items.Add(child);

        await vm.SendToQueueCommand.ExecuteAsync(parent);

        Assert.Equal("parent-2", worker.QueuedParentId);
    }
}
