/**
 * CommandRiskAnalyzer - analyzes command risk into 10 categories
 *
 * Implements DD §9.2; security-model-v1.md.
 * Intent-based sudo detection (not just string matching per DD §18.5).
 *
 * @module packages/runtime/src/security/CommandRiskAnalyzer
 */

import { basename, dirname } from 'path'

export type CommandRiskCategory =
  | 'safe_read'              // read-only operations
  | 'safe_write'             // write to project files
  | 'network_read'           // read from network (curl, wget, fetch)
  | 'network_write'          // write to network
  | 'destructive'            // rm -rf, dd, mkfs, etc.
  | 'system_modification'    // sudo, apt, yum, brew install
  | 'credential_access'      // accessing secrets, keys, passwords
  | 'process_control'        // kill, pkill, killall
  | 'file_permission'        // chmod, chown, chgrp
  | 'external_execution'     // eval, exec, source from untrusted

export interface RiskAnalysis {
  category: CommandRiskCategory
  risk_score: number        // 0-100
  reasons: string[]
  flags: string[]
  requires_confirmation: boolean
}

const DANGEROUS_PATTERNS = [
  { pattern: /^\s*rm\s+-rf?\s+/, category: 'destructive' as CommandRiskCategory, reason: 'recursive force remove' },
  { pattern: /^\s*dd\s+/, category: 'destructive' as CommandRiskCategory, reason: 'direct disk write' },
  { pattern: /^\s*mkfs\./, category: 'destructive' as CommandRiskCategory, reason: 'filesystem creation' },
  { pattern: /^\s*:\s*\|/, category: 'external_execution' as CommandRiskCategory, reason: 'pipe to shell' },
  { pattern: /^\s*source\s+/, category: 'external_execution' as CommandRiskCategory, reason: 'shell source execution' },
  { pattern: /\|\s*sh\b/, category: 'external_execution' as CommandRiskCategory, reason: 'pipe to shell' },
  { pattern: /\|\s*bash\b/, category: 'external_execution' as CommandRiskCategory, reason: 'pipe to bash' },
  { pattern: /^\s*eval\s+/, category: 'external_execution' as CommandRiskCategory, reason: 'eval execution' },
  { pattern: /^\s*exec\s+/, category: 'external_execution' as CommandRiskCategory, reason: 'exec execution' },
  { pattern: /\bkill\s+-9\b/, category: 'process_control' as CommandRiskCategory, reason: 'force kill' },
  { pattern: /\bkillall\b/, category: 'process_control' as CommandRiskCategory, reason: 'kill all processes' },
  { pattern: /\bpkill\s+-f\b/, category: 'process_control' as CommandRiskCategory, reason: 'kill by pattern' },
  { pattern: /^\s*chmod\s+-R?\s+777/, category: 'file_permission' as CommandRiskCategory, reason: 'world-writable permissions' },
  { pattern: /^\s*chown\s+-R?\s+/, category: 'file_permission' as CommandRiskCategory, reason: 'owner change' },
]

const NETWORK_READ_COMMANDS = ['curl', 'wget', 'fetch', 'http', 'https', 'axel', 'aria2c']
const NETWORK_WRITE_COMMANDS = ['ftp', 'sftp', 'scp', 'rsync', 'nc', 'netcat']
const SYSTEM_MOD_COMMANDS = [
  'sudo', 'su', 'doas', 'apt', 'apt-get', 'yum', 'dnf', 'pacman', 'brew', 'zypper',
  'dpkg', 'rpm', 'pip', 'pip3', 'npm', 'yarn', 'pnpm', 'gem', 'cargo', 'go install',
  'composer', 'helm', 'kubectl', 'docker', 'podman', 'systemctl'
]
const CREDENTIAL_PATTERNS = [
  /--password/, /-p\s+\w+/, /--secret/, /--api-key/, /--token/,
  /AWS_ACCESS_KEY/, /AWS_SECRET/, /GITHUB_TOKEN/, /GITHUB_ACTOR/, /ANTHROPIC_API_KEY/,
  /OPENAI_API_KEY/, /AZURE_KEY/, /--auth/, /-u\s+\w+/
]

export class CommandRiskAnalyzer {
  private project_root: string
  private allowed_commands: Set<string>

  constructor(project_root: string, allowed_commands: string[] = []) {
    this.project_root = project_root
    this.allowed_commands = new Set(allowed_commands)
  }

  /**
   * Analyze a command string for risk.
   * Intent-based sudo detection (DD §18.5): not just string matching.
   */
  analyze(command: string, workdir?: string): RiskAnalysis {
    const reasons: string[] = []
    const flags: string[] = []
    let category: CommandRiskCategory = 'safe_read'
    let risk_score = 0

    const trimmed = command.trim()
    const parts = this.parse_command(trimmed)
    const cmd = parts[0]?.toLowerCase() || ''

    // Check dangerous patterns first
    for (const { pattern, category: cat, reason } of DANGEROUS_PATTERNS) {
      if (pattern.test(trimmed)) {
        category = cat
        reasons.push(reason)
        risk_score = Math.max(risk_score, this.get_base_score(cat))
        break
      }
    }

    // Check for credential exposure
    if (this.contains_credentials(trimmed)) {
      category = 'credential_access'
      reasons.push('potential credential exposure')
      risk_score = Math.max(risk_score, 80)
      flags.push('credential')
    }

    // Check system modification commands (intent-based)
    if (SYSTEM_MOD_COMMANDS.includes(cmd)) {
      if (category !== 'destructive' && category !== 'external_execution') {
        category = 'system_modification'
        reasons.push(`system modification command: ${cmd}`)
        risk_score = Math.max(risk_score, 70)
      }
      flags.push(trimmed.includes('sudo') ? 'intent_sudo' : 'system_command')
    }

    // Check network read commands
    if (NETWORK_READ_COMMANDS.includes(cmd)) {
      category = 'network_read'
      reasons.push('network read operation')
      risk_score = Math.max(risk_score, 30)
      flags.push('network')
    }

    // Check network write commands
    if (NETWORK_WRITE_COMMANDS.includes(cmd)) {
      category = 'network_write'
      reasons.push('network write operation')
      risk_score = Math.max(risk_score, 50)
      flags.push('network')
    }

    // Check for intent-based sudo (DD §18.5)
    // Sudo is risky if it targets system paths or installs packages
    if (trimmed.includes('sudo') || trimmed.includes('doas')) {
      const has_install_intent = /install|update|upgrade|remove|purge|add/.test(trimmed)
      const has_system_target = /^\/(etc|usr|bin|sbin|var|boot)\//.test(trimmed.replace(/^sudo\s+/, '').split(' ').slice(1).join(' '))

      if (has_install_intent || has_system_target) {
        category = 'system_modification'
        reasons.push('sudo with install intent or system target')
        risk_score = Math.max(risk_score, 85)
        flags.push('intent_sudo', 'install_intent')
      }
    }

    // Check for project file writes (lower risk if within project)
    if (this.is_project_write(command, workdir)) {
      if (category === 'safe_read') {
        category = 'safe_write'
        reasons.push('project file write')
        risk_score = Math.max(risk_score, 20)
      }
    }

    // Default to safe_read if no risk detected
    if (reasons.length === 0) {
      category = 'safe_read'
      risk_score = 5
      reasons.push('read-only or safe operation')
    }

    return {
      category,
      risk_score: Math.min(risk_score, 100),
      reasons,
      flags,
      requires_confirmation: risk_score >= 50
    }
  }

  /**
   * Check if command writes to project files (safe if within project).
   */
  is_project_write(command: string, workdir?: string): boolean {
    const write_verbs = ['>', '>>', '|tee', '|touch', '|echo', '|printf', '|cat>', '|sed']
    const has_write_verb = write_verbs.some((v) => command.includes(v))
    if (!has_write_verb) return false

    // Check if target is within project
    const target = this.extract_write_target(command)
    if (!target) return false

    const resolved = workdir ? `${workdir}/${target}` : target
    return resolved.startsWith(this.project_root)
  }

  private parse_command(cmd: string): string[] {
    const parts: string[] = []
    let current = ''
    let in_single_quote = false
    let in_double_quote = false
    let escape_next = false

    for (const char of cmd) {
      if (escape_next) {
        current += char
        escape_next = false
        continue
      }

      if (char === '\\') {
        escape_next = true
        continue
      }

      if (char === "'" && !in_double_quote) {
        in_single_quote = !in_single_quote
        continue
      }

      if (char === '"' && !in_single_quote) {
        in_double_quote = !in_double_quote
        continue
      }

      if (char === ' ' && !in_single_quote && !in_double_quote) {
        if (current) {
          parts.push(current)
          current = ''
        }
        continue
      }

      current += char
    }

    if (current) parts.push(current)
    return parts
  }

  private extract_write_target(command: string): string | null {
    // Extract redirect target: > file, >> file, | tee file
    const match = command.match(/>\s*(\S+)|>>\s*(\S+)|\|\s*tee\s+(\S+)/)
    return match?.[1] || match?.[2] || match?.[3] || null
  }

  private contains_credentials(cmd: string): boolean {
    return CREDENTIAL_PATTERNS.some((pattern) => pattern.test(cmd))
  }

  private get_base_score(category: CommandRiskCategory): number {
    const scores: Record<CommandRiskCategory, number> = {
      safe_read: 5,
      safe_write: 20,
      network_read: 30,
      network_write: 50,
      destructive: 95,
      system_modification: 70,
      credential_access: 80,
      process_control: 60,
      file_permission: 40,
      external_execution: 90
    }
    return scores[category]
  }
}

export function createCommandRiskAnalyzer(
  project_root: string,
  allowed_commands: string[] = []
): CommandRiskAnalyzer {
  return new CommandRiskAnalyzer(project_root, allowed_commands)
}