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 BuildPlanningStartArgs_HasPlanningFlagsAndKickoffLast()
    {
        var ctx = MakeStartCtx();

        var args = WindowsTerminalLauncher.BuildPlanningStartArgs(ctx);

        Assert.Equal("--model", args[0]);
        var permIdx = args.ToList().IndexOf("--permission-mode");
        Assert.True(permIdx >= 0);
        // Default mode, NOT plan mode: plan mode gates every MCP tool call regardless of the
        // allowlist, which would prompt on the first CreateChildTask.
        Assert.Equal("default", args[permIdx + 1]);
        Assert.Contains("--allowedTools", args);
        Assert.Contains(ctx.Files.SessionDirectory, args);
        Assert.Contains(ctx.Files.SystemPromptPath, args);
        // Kickoff positional is the last token and points at the brief file.
        Assert.Contains(ctx.Files.InitialPromptPath, args[^1]);
    }

    [Fact]
    public void BuildPlanningResumeArgs_DefaultModeAllowlistsMcpAndResumes()
    {
        var args = WindowsTerminalLauncher.BuildPlanningResumeArgs("sess-9");
        Assert.Equal("--permission-mode", args[0]);
        Assert.Equal("default", args[1]);
        Assert.Equal("--allowedTools", args[2]);
        // The MCP planning tools must be re-allowlisted on resume: the CLI does not restore
        // --allowedTools across a --resume, so without it CreateChildTask would prompt again.
        Assert.Contains("mcp__claudedo__", args[3]);
        Assert.Equal(new[] { "--resume", "sess-9" }, args.Skip(4).ToArray());
    }

    [Fact]
    public void BuildResumeArgs_ResumesSession()
    {
        var args = WindowsTerminalLauncher.BuildResumeArgs("sess-42");
        Assert.Equal(new[] { "--resume", "sess-42" }, args);
    }
}
