using System.Text;

namespace AxCopilot.Services.Agent;

/// <summary>
/// Phase 19-B-EXT: 복합 Bash 명령 파서.
/// &&, ||, ;, | 로 연결된 복합 명령을 서브커맨드로 분리합니다.
/// 각 서브커맨드를 독립적으로 권한 검사하여, 하나라도 차단되면 전체를 차단합니다.
/// </summary>
public static class CompoundCommandParser
{
    /// <summary>
    /// 복합 명령을 서브커맨드 목록으로 분리합니다.
    /// 따옴표, 서브셸 내부는 분리하지 않습니다.
    /// </summary>
    public static IReadOnlyList<string> Parse(string command)
    {
        if (string.IsNullOrWhiteSpace(command))
            return Array.Empty<string>();

        var result = new List<string>();
        var current = new StringBuilder();
        var inSingleQuote = false;
        var inDoubleQuote = false;
        var parenDepth = 0;

        for (var i = 0; i < command.Length; i++)
        {
            var ch = command[i];
            var next = i + 1 < command.Length ? command[i + 1] : '\0';

            // 따옴표 토글
            if (ch == '\'' && !inDoubleQuote) { inSingleQuote = !inSingleQuote; current.Append(ch); continue; }
            if (ch == '"' && !inSingleQuote) { inDoubleQuote = !inDoubleQuote; current.Append(ch); continue; }

            // 서브셸 괄호 추적
            if (!inSingleQuote && !inDoubleQuote)
            {
                if (ch == '(') parenDepth++;
                if (ch == ')' && parenDepth > 0) parenDepth--;
            }

            // 분리자 검출 (따옴표/서브셸 밖에서만)
            if (!inSingleQuote && !inDoubleQuote && parenDepth == 0)
            {
                // && 또는 ||
                if ((ch == '&' && next == '&') || (ch == '|' && next == '|'))
                {
                    FlushCurrent(result, current);
                    i++; // 두 글자 연산자 건너뜀
                    continue;
                }

                // ; (세미콜��)
                if (ch == ';')
                {
                    FlushCurrent(result, current);
                    continue;
                }

                // | (파이프 — 단독 |만, || 아닌 경우)
                if (ch == '|' && next != '|')
                {
                    FlushCurrent(result, current);
                    continue;
                }
            }

            current.Append(ch);
        }

        FlushCurrent(result, current);
        return result;
    }

    /// <summary>
    /// 복합 명령의 각 서브커맨드를 독립 권한 검사합니다.
    /// 하나라도 Deny면 전체 Deny. 모두 Allow면 Allow. 그 외 Ask.
    /// </summary>
    public static PermissionDecision EvaluateCompound(
        string command,
        Func<string, PermissionDecision> evaluateSingle)
    {
        var subCommands = Parse(command);
        if (subCommands.Count == 0) return PermissionDecision.Ask;

        var allAllow = true;
        foreach (var sub in subCommands)
        {
            var decision = evaluateSingle(sub.Trim());
            if (decision == PermissionDecision.Deny)
                return PermissionDecision.Deny;
            if (decision != PermissionDecision.Allow)
                allAllow = false;
        }

        return allAllow ? PermissionDecision.Allow : PermissionDecision.Ask;
    }

    /// <summary>항상 에스컬레이션(차단 후보)되는 위험 패턴 목���.</summary>
    public static readonly string[] DangerousPatterns =
    {
        "rm -rf /",
        "chmod 777",
        "> ~/.bashrc",
        "> ~/.zshrc",
        ".claude/",
        ".git/config",
        ".git/hooks",
        "sed -i",
    };

    /// <summary>명령이 위험 패턴에 해당하는지 확인합니다.</summary>
    public static bool IsDangerousCommand(string command)
    {
        foreach (var pattern in DangerousPatterns)
        {
            if (command.Contains(pattern, StringComparison.OrdinalIgnoreCase))
                return true;
        }
        return false;
    }

    private static void FlushCurrent(List<string> result, StringBuilder current)
    {
        var trimmed = current.ToString().Trim();
        if (trimmed.Length > 0)
            result.Add(trimmed);
        current.Clear();
    }
}
