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;

// PlanningOperation backs the shared feedback surface for the two planning actions triggered
// from the task-row context menu (which closes the instant a click lands, so there is nothing
// per-row left to anchor an indicator to) — see docs/superpowers/plans/2026-08-11-operation-feedback.md, A4.
public class TasksIslandPlanningOperationTests : IDisposable
{
    private readonly string _dbPath;

    public TasksIslandPlanningOperationTests()
    {
        _dbPath = Path.Combine(Path.GetTempPath(), $"claudedo_planning_op_{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 GatedWorkerClient : StubWorkerClient
    {
        public override bool IsConnected => true;
        public TaskCompletionSource<object?> QueueGate { get; } = new();
        public TaskCompletionSource<object?> FinalizeGate { get; } = new();
        public bool ThrowOnQueue { get; set; }
        public bool ThrowOnFinalize { get; set; }

        public override async Task QueuePlanningSubtasksAsync(string parentTaskId, CancellationToken ct = default)
        {
            if (ThrowOnQueue) throw new InvalidOperationException("boom");
            await QueueGate.Task;
        }

        public override async Task FinalizePlanningSessionAsync(string taskId, bool queueAgentTasks = true, CancellationToken ct = default)
        {
            if (ThrowOnFinalize) throw new InvalidOperationException("boom");
            await FinalizeGate.Task;
        }
    }

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

    private static TaskRowViewModel Row(string id) => new() { Id = id, Status = TaskStatus.Idle };

    [Fact]
    public async Task QueuePlanningSubtasks_sets_PlanningOperation_IsRunning_while_pending()
    {
        var worker = new GatedWorkerClient();
        var vm = BuildViewModel(worker);
        var row = Row("parent-1");

        var run = vm.QueuePlanningSubtasksCommand.ExecuteAsync(row);
        Assert.True(vm.PlanningOperation.IsRunning);

        worker.QueueGate.SetResult(null);
        await run;

        Assert.False(vm.PlanningOperation.IsRunning);
    }

    [Fact]
    public async Task FinalizePlanningSession_sets_PlanningOperation_IsRunning_while_pending()
    {
        var worker = new GatedWorkerClient();
        var vm = BuildViewModel(worker);
        var row = Row("parent-2");

        var run = vm.FinalizePlanningSessionCommand.ExecuteAsync(row);
        Assert.True(vm.PlanningOperation.IsRunning);

        worker.FinalizeGate.SetResult(null);
        await run;

        Assert.False(vm.PlanningOperation.IsRunning);
    }

    [Fact]
    public async Task PlanningCommands_CanExecute_is_locked_while_either_operation_runs()
    {
        var worker = new GatedWorkerClient();
        var vm = BuildViewModel(worker);
        var row = Row("parent-3");

        var run = vm.QueuePlanningSubtasksCommand.ExecuteAsync(row);
        Assert.False(vm.QueuePlanningSubtasksCommand.CanExecute(row));
        Assert.False(vm.FinalizePlanningSessionCommand.CanExecute(row));

        worker.QueueGate.SetResult(null);
        await run;

        Assert.True(vm.QueuePlanningSubtasksCommand.CanExecute(row));
        Assert.True(vm.FinalizePlanningSessionCommand.CanExecute(row));
    }

    [Fact]
    public async Task QueuePlanningSubtasks_ends_the_operation_when_the_worker_call_throws()
    {
        var worker = new GatedWorkerClient { ThrowOnQueue = true };
        var vm = BuildViewModel(worker);
        var row = Row("parent-4");

        await vm.QueuePlanningSubtasksCommand.ExecuteAsync(row);

        Assert.False(vm.PlanningOperation.IsRunning);
        Assert.True(vm.QueuePlanningSubtasksCommand.CanExecute(row));
    }
}
