import type { Client } from 'ssh2'
import { execCommand } from './common.js'

export interface FirewallRule {
  chain: string
  target: string
  protocol: string
  source: string
  destination: string
  dport?: string
}

export interface FirewallChain {
  name: string
  policy: string
  rules: FirewallRule[]
}

export interface FirewallMetrics {
  type: 'iptables' | 'none'
  status: 'active' | 'inactive' | 'unknown'
  chains: FirewallChain[]
}

function parseIptablesRule(line: string): FirewallRule | null {
  if (!line.startsWith('-A ')) return null
  const rule: FirewallRule = { chain: '', target: '', protocol: 'all', source: '0.0.0.0/0', destination: '0.0.0.0/0' }
  rule.chain = line.match(/^-A\s+(\S+)/)?.[1] ?? ''
  rule.target = line.match(/-j\s+(\S+)/)?.[1] ?? ''
  rule.protocol = line.match(/-p\s+(\S+)/)?.[1] ?? 'all'
  rule.source = line.match(/-s\s+(\S+)/)?.[1] ?? '0.0.0.0/0'
  rule.destination = line.match(/-d\s+(\S+)/)?.[1] ?? '0.0.0.0/0'
  const dport = line.match(/--dport\s+(\S+)/)?.[1]
  if (dport) rule.dport = dport
  return rule
}

function parseIptablesOutput(output: string): FirewallChain[] {
  const chains = new Map<string, FirewallChain>()
  for (const rawLine of output.split('\n')) {
    const line = rawLine.trim()
    const policyMatch = line.match(/^:(\S+)\s+(\S+)/)
    if (policyMatch) {
      chains.set(policyMatch[1], { name: policyMatch[1], policy: policyMatch[2], rules: [] })
      continue
    }
    const rule = parseIptablesRule(line)
    if (rule) {
      let chain = chains.get(rule.chain)
      if (!chain) {
        chain = { name: rule.chain, policy: 'ACCEPT', rules: [] }
        chains.set(rule.chain, chain)
      }
      chain.rules.push(rule)
    }
  }
  return Array.from(chains.values())
}

export async function collectFirewallMetrics(client: Client): Promise<FirewallMetrics> {
  try {
    const result = await execCommand(client, 'iptables-save 2>/dev/null')
    if (result.stdout.includes('*filter')) {
      const chains = parseIptablesOutput(result.stdout).filter(
        (c) => c.name === 'INPUT' || c.name === 'OUTPUT' || c.name === 'FORWARD',
      )
      const hasRules = chains.some((c) => c.rules.length > 0)
      return { type: 'iptables', status: hasRules ? 'active' : 'inactive', chains }
    }
    return { type: 'none', status: 'unknown', chains: [] }
  } catch {
    return { type: 'none', status: 'unknown', chains: [] }
  }
}
