using System.IO;
using ClaudeDo.Data.Models;
using ClaudeDo.Localization;
using ClaudeDo.Ui.Localization;
using ClaudeDo.Ui.ViewModels.Islands;
using Xunit;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;

namespace ClaudeDo.Worker.Tests.UiVm;

public class TaskRowViewModelPlanningTests
{
    public TaskRowViewModelPlanningTests()
    {
        var dir = AppContext.BaseDirectory;
        while (dir is not null && !Directory.Exists(Path.Combine(dir, "src", "ClaudeDo.Localization", "locales")))
            dir = Path.GetDirectoryName(dir);
        Loc.Current = new Localizer(
            LocaleStore.Load(Path.Combine(dir!, "src", "ClaudeDo.Localization", "locales")), "en");
    }

    private static TaskRowViewModel MakeRow(
        TaskStatus status,
        string? parentTaskId = null,
        PlanningPhase phase = PlanningPhase.None)
        => new TaskRowViewModel { Id = "t", Status = status, ParentTaskId = parentTaskId, PlanningPhase = phase };

    [Fact]
    public void IdleChild_IsDraft_WhenParentIdIsNotNull()
    {
        var vm = MakeRow(TaskStatus.Idle, parentTaskId: "parent-id");
        Assert.True(vm.IsChild);
        Assert.True(vm.IsDraft);
        Assert.False(vm.IsPlanningParent);
    }

    [Fact]
    public void ActivePlanning_SetsIsPlanningParent()
    {
        var vm = MakeRow(TaskStatus.Idle, phase: PlanningPhase.Active);
        Assert.True(vm.IsPlanningParent);
        Assert.False(vm.IsChild);
        Assert.Equal("PLANNING", vm.PlanningBadge);
    }

    [Fact]
    public void FinalizedPlanning_ShowsPlannedBadge()
    {
        var vm = MakeRow(TaskStatus.Idle, phase: PlanningPhase.Finalized);
        Assert.True(vm.IsPlanningParent);
        Assert.Equal("PLANNED", vm.PlanningBadge);
    }

    [Fact]
    public void PlainIdle_NoBadge()
    {
        var vm = MakeRow(TaskStatus.Idle);
        Assert.False(vm.IsPlanningParent);
        Assert.Null(vm.PlanningBadge);
    }

    [Fact]
    public void DraftChild_CannotSendToQueue()
    {
        var vm = MakeRow(TaskStatus.Idle, parentTaskId: "parent-id");
        vm.ParentFinalized = false;
        Assert.True(vm.IsDraft);
        Assert.False(vm.IsPlanned);
        Assert.False(vm.CanSendToQueue);
    }

    [Fact]
    public void PlannedChild_CanSendToQueue()
    {
        var vm = MakeRow(TaskStatus.Idle, parentTaskId: "parent-id");
        vm.ParentFinalized = true;
        Assert.False(vm.IsDraft);
        Assert.True(vm.IsPlanned);
        Assert.True(vm.CanSendToQueue);
    }

    [Fact]
    public void StandaloneIdle_CanSendToQueue()
    {
        var vm = MakeRow(TaskStatus.Idle);
        Assert.False(vm.IsChild);
        Assert.True(vm.CanSendToQueue);
    }

    [Fact]
    public void OpenInteractiveSession_CannotSendToQueue()
    {
        // A hand-driven ConPTY session is still Idle in the DB (sessions never touch status), so
        // this has to be gated on the UI-only HasInteractiveSession flag, not on Status.
        var vm = MakeRow(TaskStatus.Idle);
        Assert.True(vm.CanSendToQueue);

        vm.HasInteractiveSession = true;
        Assert.False(vm.CanSendToQueue);

        vm.HasInteractiveSession = false;
        Assert.True(vm.CanSendToQueue);
    }

    [Fact]
    public void FinalizedParentWithChildren_CanQueuePlan()
    {
        var vm = MakeRow(TaskStatus.Idle, phase: PlanningPhase.Finalized);
        vm.HasPlanningChildren = true;
        Assert.True(vm.CanQueuePlan);
    }

    [Fact]
    public void ActiveParentWithChildren_CannotQueuePlan()
    {
        var vm = MakeRow(TaskStatus.Idle, phase: PlanningPhase.Active);
        vm.HasPlanningChildren = true;
        Assert.False(vm.CanQueuePlan);
    }

    [Fact]
    public void FinalizedParentWithoutChildren_CannotQueuePlan()
    {
        var vm = MakeRow(TaskStatus.Idle, phase: PlanningPhase.Finalized);
        Assert.False(vm.CanQueuePlan);
    }

    [Fact]
    public void ActivePlanningParent_CannotSendToQueue()
    {
        var vm = MakeRow(TaskStatus.Idle, phase: PlanningPhase.Active);
        vm.HasPlanningChildren = true;
        Assert.False(vm.CanSendToQueue);
    }

    [Fact]
    public void FinalizedParentWithChildren_CanSendToQueue()
    {
        var vm = MakeRow(TaskStatus.Idle, phase: PlanningPhase.Finalized);
        vm.HasPlanningChildren = true;
        Assert.True(vm.CanSendToQueue);
    }

    [Fact]
    public void ActivePlanning_CanFinalizePlanning()
    {
        var vm = MakeRow(TaskStatus.Idle, phase: PlanningPhase.Active);
        Assert.True(vm.CanFinalizePlanning);
    }

    [Fact]
    public void FinalizedPlanning_CannotFinalizePlanning()
    {
        var vm = MakeRow(TaskStatus.Idle, phase: PlanningPhase.Finalized);
        Assert.False(vm.CanFinalizePlanning);
    }

    [Fact]
    public void PlainIdle_CannotFinalizePlanning()
    {
        var vm = MakeRow(TaskStatus.Idle);
        Assert.False(vm.CanFinalizePlanning);
    }

    [Fact]
    public void ChildWithParentInView_RendersAsChild()
    {
        var vm = MakeRow(TaskStatus.Idle, parentTaskId: "parent-id");
        Assert.True(vm.ParentInView);   // default
        Assert.True(vm.ShowAsChild);
        Assert.True(vm.IsDraft);
    }

    [Fact]
    public void OrphanedChild_RendersFlat_WithNoDraftOrPlannedBadge()
    {
        // Parent absent from the view (e.g. removed from My Day, or daily-prep placed a lone
        // child there): the row stays a child by data but must read as a normal top-level task.
        var draftOrphan = MakeRow(TaskStatus.Idle, parentTaskId: "missing");
        draftOrphan.ParentInView = false;
        Assert.True(draftOrphan.IsChild);
        Assert.False(draftOrphan.ShowAsChild);
        Assert.False(draftOrphan.IsDraft);

        var plannedOrphan = MakeRow(TaskStatus.Idle, parentTaskId: "missing");
        plannedOrphan.ParentFinalized = true;
        plannedOrphan.ParentInView = false;
        Assert.False(plannedOrphan.ShowAsChild);
        Assert.False(plannedOrphan.IsPlanned);
        Assert.False(plannedOrphan.IsDraft);
    }

    [Fact]
    public void CanAddToMyDay_TrueOnlyWhenNotInMyDayAndNotDone()
    {
        var row = MakeRow(TaskStatus.Idle);
        Assert.True(row.CanAddToMyDay);   // idle, not yet in My Day

        row.IsMyDay = true;
        Assert.False(row.CanAddToMyDay);  // already in My Day

        row.IsMyDay = false;
        row.Done = true;
        Assert.False(row.CanAddToMyDay);  // done tasks don't belong in today's focus
    }
}
