using System.Text.Json.Serialization;

namespace AxCopilot.Services.Agent;

/// <summary>Phase 17-F: 권한 모드.</summary>
public enum PermissionMode
{
    Default,            // 잠재적으로 위험한 작업에 확인 요청 (기존 Ask 모드)
    AcceptEdits,        // 파일 편집 자동승인, bash/process 확인 유지 (신규)
    Plan,               // 읽기 전용, 쓰기 차단 (기존)
    BypassPermissions,  // 모든 확인 건너뜀 (기존 Auto 모드, 자동화 전용)
}

/// <summary>권한 동작.</summary>
public enum PermissionBehavior { Allow, Deny, Ask }

/// <summary>권한 규칙 하나. 도구명 + 입력 패턴 기반 자동 허용/차단.</summary>
public class PermissionRule
{
    /// <summary>도구 이름. "process", "file_edit", "mcp__server__tool" 등.</summary>
    [JsonPropertyName("tool")]
    public string ToolName { get; set; } = "";

    /// <summary>도구 입력 패턴. null이면 모든 입력에 매칭. "git *", "rm -rf *" 등.</summary>
    [JsonPropertyName("pattern")]
    public string? Pattern { get; set; }

    /// <summary>동작: Allow | Deny | Ask</summary>
    [JsonPropertyName("behavior")]
    public PermissionBehavior Behavior { get; set; } = PermissionBehavior.Allow;
}

/// <summary>권한 결정.</summary>
public enum PermissionDecision { Allow, Deny, Ask }

// ── Chain of Responsibility 패턴 ──────────────────────────────────────────

/// <summary>권한 처리기 추상 기반 클래스.</summary>
public abstract class PermissionHandler
{
    protected PermissionHandler? _next;

    public PermissionHandler SetNext(PermissionHandler next)
    {
        _next = next;
        return next;
    }

    public abstract PermissionDecision? Handle(string toolName, string input);
}

/// <summary>Deny 규칙 핸들러.</summary>
public class DenyRuleHandler : PermissionHandler
{
    private readonly IReadOnlyList<PermissionRule> _rules;

    public DenyRuleHandler(IReadOnlyList<PermissionRule> rules)
        => _rules = rules;

    public override PermissionDecision? Handle(string toolName, string input)
    {
        if (_rules.Any(r => r.Behavior == PermissionBehavior.Deny && Matches(r, toolName, input)))
            return PermissionDecision.Deny;
        return _next?.Handle(toolName, input);
    }

    private static bool Matches(PermissionRule rule, string toolName, string input)
    {
        if (!toolName.Equals(rule.ToolName, StringComparison.OrdinalIgnoreCase) &&
            !toolName.StartsWith(rule.ToolName, StringComparison.OrdinalIgnoreCase))
            return false;
        if (rule.Pattern == null) return true;
        return GlobMatcher.IsMatch(input, rule.Pattern);
    }
}

/// <summary>Allow 규칙 핸들러.</summary>
public class AllowRuleHandler : PermissionHandler
{
    private readonly IReadOnlyList<PermissionRule> _rules;

    public AllowRuleHandler(IReadOnlyList<PermissionRule> rules)
        => _rules = rules;

    public override PermissionDecision? Handle(string toolName, string input)
    {
        if (_rules.Any(r => r.Behavior == PermissionBehavior.Allow && Matches(r, toolName, input)))
            return PermissionDecision.Allow;
        return _next?.Handle(toolName, input);
    }

    private static bool Matches(PermissionRule rule, string toolName, string input)
    {
        if (!toolName.Equals(rule.ToolName, StringComparison.OrdinalIgnoreCase) &&
            !toolName.StartsWith(rule.ToolName, StringComparison.OrdinalIgnoreCase))
            return false;
        if (rule.Pattern == null) return true;
        return GlobMatcher.IsMatch(input, rule.Pattern);
    }
}

/// <summary>AcceptEdits 모드 핸들러: 파일 편집 도구 자동 승인.</summary>
public class AcceptEditsHandler : PermissionHandler
{
    private readonly PermissionMode _mode;

    private static readonly HashSet<string> _editTools = new(StringComparer.OrdinalIgnoreCase)
    {
        "file_edit", "file_write", "script_create",
        "docx_create", "html_create", "xlsx_create", "pptx_create", "csv_create",
    };

    public AcceptEditsHandler(PermissionMode mode) => _mode = mode;

    public override PermissionDecision? Handle(string toolName, string input)
    {
        if (_mode == PermissionMode.AcceptEdits && _editTools.Contains(toolName))
            return PermissionDecision.Allow;
        return _next?.Handle(toolName, input);
    }
}

/// <summary>Plan 모드 핸들러: 쓰기 작업 차단.</summary>
public class PlanModeHandler : PermissionHandler
{
    private readonly PermissionMode _mode;

    private static readonly HashSet<string> _writeTools = new(StringComparer.OrdinalIgnoreCase)
    {
        "file_edit", "file_write", "file_delete", "script_create",
        "process", "bash", "build_run",
        "docx_create", "html_create", "xlsx_create", "pptx_create",
    };

    public PlanModeHandler(PermissionMode mode) => _mode = mode;

    public override PermissionDecision? Handle(string toolName, string input)
    {
        if (_mode == PermissionMode.Plan && _writeTools.Contains(toolName))
            return PermissionDecision.Deny;
        return _next?.Handle(toolName, input);
    }
}

/// <summary>BypassPermissions 모드 핸들러: 모두 허용.</summary>
public class BypassHandler : PermissionHandler
{
    private readonly PermissionMode _mode;
    public BypassHandler(PermissionMode mode) => _mode = mode;

    public override PermissionDecision? Handle(string toolName, string input)
    {
        if (_mode == PermissionMode.BypassPermissions)
            return PermissionDecision.Allow;
        return _next?.Handle(toolName, input);
    }
}

/// <summary>
/// 권한 결정 서비스.
/// Chain: Deny규칙 → Allow규칙 → AcceptEdits/Plan/Bypass모드 → 기본(Ask)
/// </summary>
public class PermissionDecisionService
{
    private readonly PermissionHandler _chain;
    private readonly PermissionMode _mode;

    public PermissionDecisionService(
        PermissionMode mode,
        IReadOnlyList<PermissionRule> allowRules,
        IReadOnlyList<PermissionRule> denyRules)
    {
        _mode = mode;

        var denyHandler        = new DenyRuleHandler(denyRules);
        var allowHandler       = new AllowRuleHandler(allowRules);
        var acceptEditsHandler = new AcceptEditsHandler(mode);
        var planHandler        = new PlanModeHandler(mode);
        var bypassHandler      = new BypassHandler(mode);

        // Chain 조립
        denyHandler
            .SetNext(allowHandler)
            .SetNext(acceptEditsHandler)
            .SetNext(planHandler)
            .SetNext(bypassHandler);

        _chain = denyHandler;
    }

    public PermissionDecision Decide(string toolName, string input)
    {
        // Phase 19-B-EXT: Bash/process 복합 명령은 서브커맨드별 개별 검사
        if (IsBashTool(toolName) && !string.IsNullOrWhiteSpace(input))
        {
            // 위험 패턴 즉시 차단
            if (CompoundCommandParser.IsDangerousCommand(input))
                return PermissionDecision.Deny;

            return CompoundCommandParser.EvaluateCompound(
                input,
                sub => _chain.Handle(toolName, sub) ?? PermissionDecision.Ask);
        }

        return _chain.Handle(toolName, input) ?? PermissionDecision.Ask;
    }

    private static bool IsBashTool(string toolName)
        => toolName is "process" or "bash" or "build_run";

    /// <summary>MCP 도구 허용 여부 확인. mcp__server 및 mcp__server__tool 패턴 처리.</summary>
    public bool IsMcpToolAllowed(string serverName, string toolName)
    {
        var fullName      = $"mcp__{serverName}__{toolName}";
        var serverPattern = $"mcp__{serverName}";

        if (Decide(fullName, string.Empty) == PermissionDecision.Deny) return false;
        if (Decide(serverPattern, string.Empty) == PermissionDecision.Deny) return false;
        return true;
    }

    public PermissionMode Mode => _mode;
}
