using System.IO;
using ClaudeDo.Localization;
using ClaudeDo.Ui.Localization;
using ClaudeDo.Ui.Services;
using ClaudeDo.Ui.ViewModels.Modals;

namespace ClaudeDo.Ui.Tests.ViewModels;

public class WorktreesOverviewModalErrorTests
{
    public WorktreesOverviewModalErrorTests()
    {
        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 sealed class ThrowingWorker : StubWorkerClient
    {
        public string ExceptionMessage { get; init; } = "worktree is locked by another process";
        public override Task<List<WorktreeOverviewDto>> GetWorktreesOverviewAsync(string? listId) =>
            throw new Exception(ExceptionMessage);
        public override Task<WorktreeCleanupDto?> CleanupFinishedWorktreesAsync(string? listId = null) =>
            throw new Exception(ExceptionMessage);
        public override Task<ForceRemoveResultDto?> ForceRemoveWorktreeAsync(string taskId) =>
            throw new Exception(ExceptionMessage);
    }

    private static WorktreesOverviewModalViewModel NewVm(ThrowingWorker worker) =>
        new(worker, () => null!, new MergeCoordinator());

    [Fact]
    public async Task CleanupFinished_WhenWorkerThrows_ShowsExceptionMessage()
    {
        var worker = new ThrowingWorker();
        var vm = NewVm(worker);

        await vm.CleanupFinishedCommand.ExecuteAsync(null);

        Assert.NotNull(vm.StatusMessage);
        Assert.Contains(worker.ExceptionMessage, vm.StatusMessage);
        Assert.False(vm.CleanupStatus.IsRunning);
    }

    [Fact]
    public async Task ForceRemove_WhenWorkerThrows_ShowsExceptionMessage_AndKeepsRow()
    {
        var worker = new ThrowingWorker();
        var vm = NewVm(worker);
        var row = new WorktreeOverviewRowViewModel
        {
            TaskId = "task-1",
            TaskTitle = "Task 1",
            TaskStatus = ClaudeDo.Data.Models.TaskStatus.Idle,
            State = ClaudeDo.Data.Models.WorktreeState.Active,
        };
        vm.AddRowForTest(row);

        await vm.ForceRemoveCommand.ExecuteAsync(row);

        Assert.NotNull(vm.StatusMessage);
        Assert.Contains(worker.ExceptionMessage, vm.StatusMessage);
        Assert.Contains(row, vm.Rows);
        Assert.False(vm.ForceRemoveStatus.IsRunning);
    }

    [Fact]
    public async Task Refresh_WhenWorkerThrows_ResetsRefreshStatus()
    {
        var worker = new ThrowingWorker();
        var vm = NewVm(worker);

        await Assert.ThrowsAsync<Exception>(() => vm.RefreshCommand.ExecuteAsync(null));

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

    [Fact]
    public async Task Discard_WhenConfirmDeclined_LeavesStateUnchanged()
    {
        var worker = new ThrowingWorker();
        var vm = NewVm(worker);
        vm.ConfirmAction = _ => Task.FromResult(false);
        var row = new WorktreeOverviewRowViewModel
        {
            TaskId = "task-1",
            TaskTitle = "Task 1",
            TaskStatus = ClaudeDo.Data.Models.TaskStatus.Idle,
            State = ClaudeDo.Data.Models.WorktreeState.Active,
        };
        vm.AddRowForTest(row);

        await vm.DiscardCommand.ExecuteAsync(row);

        Assert.Equal(ClaudeDo.Data.Models.WorktreeState.Active, row.State);
        Assert.Null(vm.StatusMessage);
    }
}
