import type { PermissionResult, PermissionBehavior } from '../tools/core/ToolPermissions'
import type { PermissionContext } from './PermissionContext'
import { matchRule, cleanupExpiredRules } from './always-allow-rules'
import { auditLog } from '@/lib/audit/AuditLog'

export type PolicyRule = {
  toolName: string | string[]
  behavior: PermissionBehavior
  reason?: string
  conditions?: Array<{
    field: string
    operator: 'eq' | 'contains' | 'regex'
    value: string
  }>
}

export class PolicyResolver {
  private rules: PolicyRule[] = []

  addRule(rule: PolicyRule): void {
    this.rules.push(rule)
  }

  addRules(rules: PolicyRule[]): void {
    for (const r of rules) this.addRule(r)
  }

  clearRules(): void {
    this.rules = []
  }

  resolve(toolName: string, input: unknown, _ctx: PermissionContext): PermissionResult | null {
    for (const rule of this.rules) {
      const names = Array.isArray(rule.toolName) ? rule.toolName : [rule.toolName]
      if (!names.includes(toolName)) continue

      if (rule.conditions) {
        const allMatch = rule.conditions.every(c => {
          const inputRecord = input as Record<string, unknown>
          const val = String(inputRecord[c.field] ?? '')
          switch (c.operator) {
            case 'eq': return val === c.value
            case 'contains': return val.includes(c.value)
            case 'regex': return new RegExp(c.value).test(val)
            default: return false
          }
        })
        if (!allMatch) continue
      }

      return { behavior: rule.behavior, reason: rule.reason }
    }

    return null
  }

  resolveWithMode(toolName: string, input: unknown, ctx: PermissionContext): PermissionResult {
    if (ctx.alwaysAllowRules && ctx.alwaysAllowRules.length > 0) {
      const activeRules = cleanupExpiredRules(ctx.alwaysAllowRules)
      ctx.alwaysAllowRules = activeRules
      for (const rule of activeRules) {
        if (matchRule(rule, toolName, input)) {
          return { behavior: 'allow', reason: `Matched always-allow rule: ${rule.toolName}` }
        }
      }
    }
    if (ctx.permissions.alwaysAllow.includes(toolName)) {
      // Tool is permitted for this role — return 'ask' so the tool's own
      // per-invocation permission tier (allow/ask/deny) is still respected.
      return { behavior: 'ask', reason: 'In always-allow list' }
    }
    if (ctx.permissions.alwaysDeny.includes(toolName)) {
      return { behavior: 'deny', reason: 'In always-deny list' }
    }

    const ruleResult = this.resolve(toolName, input, ctx)
    if (ruleResult) return ruleResult

    if (ctx.mode === 'autonomous') return { behavior: 'allow', reason: 'Autonomous mode' }
    if (ctx.mode === 'bypass') return { behavior: 'allow', reason: 'Permissions bypassed' }

    // Default-deny: log and return deny for unknown tools
    auditLog.recordPermissionDenied(
      ctx.role,
      toolName,
      `Tool "${toolName}" denied for role "${ctx.role}" — no matching policy rule`,
    )

    return { behavior: 'deny', reason: `Tool "${toolName}" not permitted for role "${ctx.role}"` }
  }
}
