using System.Text.Json;

namespace ClaudeDo.Worker.Runner;

public sealed record ClaudeRunConfig(
    string? Model,
    string? SystemPrompt,
    string? AgentPath,
    string? ResumeSessionId,
    int? MaxTurns = null,
    string? PermissionMode = null
);

public sealed class ClaudeArgsBuilder
{
    private static readonly string ResultSchema = JsonSerializer.Serialize(new
    {
        type = "object",
        properties = new
        {
            summary = new { type = "string" },
            files_changed = new { type = "array", items = new { type = "string" } },
            commit_type = new { type = "string" },
        },
        required = new[] { "summary" },
    });

    public string Build(ClaudeRunConfig config)
    {
        var args = new List<string>
        {
            "-p",
            "--output-format stream-json",
            "--verbose",
        };

        var permissionMode = string.IsNullOrWhiteSpace(config.PermissionMode) ? "bypassPermissions" : config.PermissionMode;
        if (permissionMode.Equals("bypassPermissions", StringComparison.OrdinalIgnoreCase))
            args.Add("--dangerously-skip-permissions");
        else
            args.Add($"--permission-mode {permissionMode}");

        if (config.Model is not null)
            args.Add($"--model {config.Model}");

        if (config.MaxTurns is int turns && turns > 0)
            args.Add($"--max-turns {turns}");

        if (config.SystemPrompt is not null)
            args.Add($"--append-system-prompt {Escape(config.SystemPrompt)}");

        if (config.AgentPath is not null)
        {
            var agentJson = JsonSerializer.Serialize(new[] { new { file = config.AgentPath } });
            args.Add($"--agents {Escape(agentJson)}");
        }

        args.Add($"--json-schema {Escape(ResultSchema)}");

        if (config.ResumeSessionId is not null)
            args.Add($"--resume {config.ResumeSessionId}");

        return string.Join(" ", args);
    }

    private static string Escape(string value)
    {
        if (value.Contains(' ') || value.Contains('"') || value.Contains('\'')
            || value.Contains('\t') || value.Contains('\n') || value.Contains('\r'))
        {
            var escaped = value
                .Replace("\\", "\\\\")
                .Replace("\"", "\\\"")
                .Replace("\n", "\\n")
                .Replace("\r", "\\r")
                .Replace("\t", "\\t");
            return $"\"{escaped}\"";
        }
        return value;
    }
}
