using ClaudeDo.Worker.Planning;

namespace ClaudeDo.Worker.Tests.Planning;

public sealed class WindowsTerminalLauncherTests
{
    private static PlanningSessionStartContext MakeStartCtx(string? wd = null)
    {
        var workingDir = wd ?? Path.GetTempPath();
        var dir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
        Directory.CreateDirectory(dir);
        return new PlanningSessionStartContext(
            ParentTaskId: "task-1",
            WorkingDir: workingDir,
            Token: "test-token",
            WorktreePath: workingDir,
            BranchName: "claudedo/planning/task1",
            Files: new PlanningSessionFiles(
                SessionDirectory: dir,
                SystemPromptPath: Path.Combine(dir, "system-prompt.md"),
                InitialPromptPath: Path.Combine(dir, "initial-prompt.txt")));
    }

    [Fact]
    public async Task LaunchPlanningStartAsync_WorkingDirMissing_Throws()
    {
        var ctx = MakeStartCtx(wd: Path.Combine(Path.GetTempPath(), "nonexistent_" + Guid.NewGuid()));
        var sut = new WindowsTerminalLauncher(wtPath: "wt", claudePath: "claude");
        var ex = await Assert.ThrowsAsync<TerminalLaunchException>(() =>
            sut.LaunchPlanningStartAsync(ctx, CancellationToken.None));
        Assert.Contains("Working directory", ex.Message);
    }

    [Fact]
    public async Task LaunchPlanningStartAsync_WtMissing_Throws()
    {
        var ctx = MakeStartCtx();
        File.WriteAllText(ctx.Files.SystemPromptPath, "sp");
        File.WriteAllText(ctx.Files.InitialPromptPath, "ip");

        var sut = new WindowsTerminalLauncher(
            wtPath: "C:/no/such/wt.exe",
            claudePath: "claude");
        var ex = await Assert.ThrowsAsync<TerminalLaunchException>(() =>
            sut.LaunchPlanningStartAsync(ctx, CancellationToken.None));
        Assert.Contains("Windows Terminal", ex.Message);
    }

    [Fact]
    public void BuildPlanningStartCommand_SeedsViaBriefFile_NotInlineText()
    {
        var ctx = MakeStartCtx();

        var command = WindowsTerminalLauncher.BuildPlanningStartCommand("claude.exe", ctx);

        // The brief is read from a file: the kickoff references the brief path, and its
        // directory is exposed via --add-dir so the Read tool can open it.
        Assert.Contains(ctx.Files.InitialPromptPath, command);
        Assert.Contains($"--add-dir' '{ctx.Files.SessionDirectory}", command);

        // The positional kickoff must follow the single-value --append-system-prompt-file
        // flag, or a preceding variadic flag would swallow it.
        var appendIdx = command.IndexOf("--append-system-prompt-file", StringComparison.Ordinal);
        var addDirIdx = command.IndexOf("--add-dir", StringComparison.Ordinal);
        Assert.True(appendIdx > addDirIdx, "--append-system-prompt-file must come after --add-dir");
        Assert.True(command.IndexOf(ctx.Files.InitialPromptPath, StringComparison.Ordinal) > appendIdx,
            "the kickoff prompt must be the last (positional) token");

        // The legacy env-var indirection is gone.
        Assert.DoesNotContain("CLAUDEDO_LAUNCH_PROMPT", command);
    }

    [Fact]
    public void BuildResumeCommand_ResumesSessionSingleQuoted()
    {
        var command = WindowsTerminalLauncher.BuildResumeCommand("claude.exe", "sess-42");

        Assert.Contains("--resume", command);
        // The session id is single-quoted so ';' and friends pass through untouched.
        Assert.Contains("'--resume' 'sess-42'", command);
        // A plain resume drives the real interactive TUI — no planning-only flags.
        Assert.DoesNotContain("--permission-mode", command);
        Assert.DoesNotContain("--append-system-prompt-file", command);
    }

    [Fact]
    public async Task LaunchResumeAsync_WorkingDirMissing_Throws()
    {
        var sut = new WindowsTerminalLauncher(wtPath: "wt", claudePath: "claude");
        var missing = Path.Combine(Path.GetTempPath(), "nonexistent_" + Guid.NewGuid());
        var ex = await Assert.ThrowsAsync<TerminalLaunchException>(() =>
            sut.LaunchResumeAsync(missing, "sess-1", CancellationToken.None));
        Assert.Contains("Working directory", ex.Message);
    }
}
