// Claude CLI flags (verified 2026-04-23 via Context7):
//   Thinking budget:   env var MAX_THINKING_TOKENS=20000 (no CLI flag exists)
//   Allowed-tools:     --allowedTools (camelCase), comma-separated tokens
//   System prompt:     --append-system-prompt-file <path>  (file form)
//   Session ID:        no pre-assign flag; resume with --resume <id>
// Launch model: wt.exe directly spawns claude.exe via argv (UseShellExecute=false).
// No cmd /k shim — arbitrary initial-prompt content would be re-parsed by cmd.exe otherwise.

using System.Diagnostics;
using ClaudeDo.Data.Models;

namespace ClaudeDo.Worker.Planning;

public sealed class WindowsTerminalPlanningLauncher : IPlanningTerminalLauncher
{
    private const string AllowedTools = "mcp__claudedo__*,Read,Grep,Glob,WebFetch,WebSearch,Skill";
    private const string Model = ModelRegistry.PlanningAlias;

    private readonly string _wtPath;
    private readonly string _claudePath;

    public WindowsTerminalPlanningLauncher(string wtPath, string claudePath)
    {
        _wtPath = wtPath;
        _claudePath = claudePath;
    }

    public Task LaunchStartAsync(PlanningSessionStartContext ctx, CancellationToken cancellationToken)
    {
        if (!Directory.Exists(ctx.WorkingDir))
            throw new PlanningLaunchException($"Working directory does not exist: {ctx.WorkingDir}");

        if (!File.Exists(ctx.Files.SystemPromptPath))
            throw new PlanningLaunchException($"System prompt file not found: {ctx.Files.SystemPromptPath}");
        if (!File.Exists(ctx.Files.InitialPromptPath))
            throw new PlanningLaunchException($"Initial prompt file not found: {ctx.Files.InitialPromptPath}");

        var resolvedWt = Resolve(_wtPath);
        if (resolvedWt is null)
            throw new PlanningLaunchException($"Windows Terminal not found: {_wtPath}");

        var resolvedClaude = Resolve(_claudePath);
        if (resolvedClaude is null)
            throw new PlanningLaunchException($"claude executable not found: {_claudePath}");

        var psi = new ProcessStartInfo
        {
            FileName = resolvedWt,
            UseShellExecute = false,
            CreateNoWindow = false,
        };

        psi.Environment["MAX_THINKING_TOKENS"] = "20000";
        psi.Environment["CLAUDEDO_PLANNING_TOKEN"] = ctx.Token;

        // Arg order: --allowedTools is variadic (space-separated). The positional
        // prompt must follow a single-value flag, or it will be swallowed.
        // --append-system-prompt-file serves as that buffer.
        psi.ArgumentList.Add("-d");
        psi.ArgumentList.Add(ctx.WorkingDir);
        psi.ArgumentList.Add(resolvedClaude);
        psi.ArgumentList.Add("--model");
        psi.ArgumentList.Add(Model);
        psi.ArgumentList.Add("--permission-mode");
        psi.ArgumentList.Add("plan");
        psi.ArgumentList.Add("--allowedTools");
        psi.ArgumentList.Add(AllowedTools);
        psi.ArgumentList.Add("--append-system-prompt-file");
        psi.ArgumentList.Add(ctx.Files.SystemPromptPath);
        psi.ArgumentList.Add(File.ReadAllText(ctx.Files.InitialPromptPath));

        var proc = Process.Start(psi)
            ?? throw new PlanningLaunchException("Failed to start Windows Terminal process.");

        return Task.CompletedTask;
    }

    public Task LaunchInteractiveAsync(InteractiveLaunchContext ctx, CancellationToken cancellationToken)
    {
        if (!Directory.Exists(ctx.WorkingDir))
            throw new PlanningLaunchException($"Working directory does not exist: {ctx.WorkingDir}");

        var resolvedWt = Resolve(_wtPath)
            ?? throw new PlanningLaunchException($"Windows Terminal not found: {_wtPath}");
        var resolvedClaude = Resolve(_claudePath)
            ?? throw new PlanningLaunchException($"claude executable not found: {_claudePath}");

        var psi = new ProcessStartInfo
        {
            FileName = resolvedWt,
            UseShellExecute = false,
            CreateNoWindow = false,
        };

        psi.Environment["MAX_THINKING_TOKENS"] = "20000";

        psi.ArgumentList.Add("-d");
        psi.ArgumentList.Add(ctx.WorkingDir);
        psi.ArgumentList.Add(resolvedClaude);
        psi.ArgumentList.Add("--model");
        psi.ArgumentList.Add(Model);
        psi.ArgumentList.Add("--permission-mode");
        psi.ArgumentList.Add("auto");
        psi.ArgumentList.Add(ctx.InitialPrompt);

        var proc = Process.Start(psi)
            ?? throw new PlanningLaunchException("Failed to start Windows Terminal process.");

        return Task.CompletedTask;
    }

    public Task LaunchResumeAsync(PlanningSessionResumeContext ctx, CancellationToken cancellationToken)
    {
        if (!Directory.Exists(ctx.WorkingDir))
            throw new PlanningLaunchException($"Working directory does not exist: {ctx.WorkingDir}");

        var resolvedWt = Resolve(_wtPath);
        if (resolvedWt is null)
            throw new PlanningLaunchException($"Windows Terminal not found: {_wtPath}");

        var resolvedClaude = Resolve(_claudePath);
        if (resolvedClaude is null)
            throw new PlanningLaunchException($"claude executable not found: {_claudePath}");

        var psi = new ProcessStartInfo
        {
            FileName = resolvedWt,
            UseShellExecute = false,
            CreateNoWindow = false,
        };

        psi.Environment["CLAUDEDO_PLANNING_TOKEN"] = ctx.Token;

        psi.ArgumentList.Add("-d");
        psi.ArgumentList.Add(ctx.WorkingDir);
        psi.ArgumentList.Add(resolvedClaude);
        psi.ArgumentList.Add("--permission-mode");
        psi.ArgumentList.Add("plan");
        psi.ArgumentList.Add("--resume");
        psi.ArgumentList.Add(ctx.ClaudeSessionId);

        var proc = Process.Start(psi)
            ?? throw new PlanningLaunchException("Failed to start Windows Terminal process.");

        return Task.CompletedTask;
    }

    private static string? Resolve(string pathOrName)
    {
        if (File.Exists(pathOrName))
            return pathOrName;

        // Try PATH resolution
        var envPath = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
        var extensions = new[] { "", ".exe", ".cmd", ".bat" };
        foreach (var dir in envPath.Split(Path.PathSeparator))
        {
            foreach (var ext in extensions)
            {
                var candidate = Path.Combine(dir, pathOrName + ext);
                if (File.Exists(candidate))
                    return candidate;
            }
        }

        return null;
    }
}
