using AxCopilot.Models;

namespace AxCopilot.Services.Agent;

/// <summary>
/// Phase 17-F: AgentLoopService — 권한 시스템 고도화 통합.
/// · PermissionsConfig(설정) → PermissionDecisionService(런타임) 변환 및 캐시
/// · acceptEdits 모드: 파일 편집 도구 자동 승인, bash/process 확인 유지
/// · 패턴 기반 Allow/Deny 규칙: process(git *) 허용, process(rm -rf *) 차단 등
/// · Chain: Deny규칙 → Allow규칙 → AcceptEdits/Plan/Bypass모드 → 기본(Ask)
/// </summary>
public partial class AgentLoopService
{
    // 세션당 PermissionDecisionService 캐시 (모드 변경 시 재생성)
    private PermissionDecisionService? _permissionService;
    private string? _cachedPermissionMode;

    /// <summary>
    /// 현재 설정 기반 PermissionDecisionService를 반환합니다.
    /// 모드 변경 시 자동 재생성됩니다.
    /// </summary>
    internal PermissionDecisionService GetPermissionService()
    {
        var perms   = _settings.Settings.Llm.Permissions;
        var modeStr = perms.Mode ?? "default";

        if (_permissionService != null && _cachedPermissionMode == modeStr)
            return _permissionService;

        var mode = modeStr switch
        {
            "acceptEdits"       => PermissionMode.AcceptEdits,
            "plan"              => PermissionMode.Plan,
            "bypassPermissions" => PermissionMode.BypassPermissions,
            _                   => PermissionMode.Default,
        };

        // 설정 PermissionRuleEntry → 런타임 PermissionRule 변환
        var allowRules = perms.AllowRules
            .Where(r => !string.IsNullOrEmpty(r.ToolName))
            .Select(r => new PermissionRule
            {
                ToolName = r.ToolName,
                Pattern  = r.Pattern,
                Behavior = PermissionBehavior.Allow,
            })
            .ToList();

        var denyRules = perms.DenyRules
            .Where(r => !string.IsNullOrEmpty(r.ToolName))
            .Select(r => new PermissionRule
            {
                ToolName = r.ToolName,
                Pattern  = r.Pattern,
                Behavior = PermissionBehavior.Deny,
            })
            .ToList();

        _permissionService    = new PermissionDecisionService(mode, allowRules, denyRules);
        _cachedPermissionMode = modeStr;

        LogService.Debug($"[Permissions] 모드={mode}, Allow={allowRules.Count}개, Deny={denyRules.Count}개");
        return _permissionService;
    }

    /// <summary>
    /// 도구 호출 권한을 평가합니다.
    /// · Deny  → 즉시 차단 (사용자 확인 없음)
    /// · Allow → 무조건 허용 (CheckDecisionRequired 스킵)
    /// · Ask   → 기존 CheckDecisionRequired 흐름으로 위임
    /// </summary>
    internal PermissionDecision EvaluateToolPermission(string toolName, string input)
    {
        try
        {
            var decision = GetPermissionService().Decide(toolName, input);

            // 이벤트 로그 — Deny/Allow만 기록 (Ask는 기존 흐름에서 처리)
            if (decision != PermissionDecision.Ask)
                _ = _eventLog?.AppendAsync(AgentEventLogType.ToolResult,
                    System.Text.Json.JsonSerializer.Serialize(new
                    {
                        type     = "permission",
                        toolName,
                        decision = decision.ToString(),
                        mode     = _cachedPermissionMode ?? "default",
                    }));

            return decision;
        }
        catch (Exception ex)
        {
            LogService.Warn($"[Permissions] 권한 평가 실패: {ex.Message}");
            return PermissionDecision.Ask; // 실패 시 기존 흐름으로 폴백
        }
    }

    /// <summary>MCP 도구 허용 여부를 확인합니다. 차단된 서버/도구는 false.</summary>
    internal bool CheckMcpToolAllowed(string serverName, string toolName)
    {
        try { return GetPermissionService().IsMcpToolAllowed(serverName, toolName); }
        catch { return true; }
    }
}
