import type { CreateHijackEventInput } from './types'
import type { HijackAlertsDatabaseClient } from './db-client'

export interface HijackDetectionResult {
  detected: boolean
  event?: CreateHijackEventInput
  reason?: string
}

export interface HijackClassification {
  hijack_type: 'MOAS' | 'HIJACK' | 'LEAK'
  severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW'
  baseDescription: string
}

/**
 * Deterministic hijack classification based on network characteristics
 * - MOAS (Multiple Origin AS): Multiple ASNs legitimately announce same prefix
 * - HIJACK: Unauthorized ASN announcing prefix it doesn't own
 * - LEAK: ASN accidentally leaking customer or upstream prefix
 */
export function classifyHijack(
  expectedAsn: number,
  detectedAsns: number[],
  prefix: string
): HijackClassification {
  if (!detectedAsns.length) {
    return {
      hijack_type: 'HIJACK',
      severity: 'HIGH',
      baseDescription: 'Prefix announced but no origin ASN detected'
    }
  }

  const prefixParts = prefix.split('/')
  const prefixLength = prefixParts.length > 1 ? parseInt(prefixParts[1]) : 0

  // MOAS detection: Multiple legitimate ASNs for same prefix
  if (detectedAsns.includes(expectedAsn) && detectedAsns.length > 1) {
    return {
      hijack_type: 'MOAS',
      severity: 'MEDIUM',
      baseDescription: `Multiple Origin AS detected: ${detectedAsns.join(', ')}`
    }
  }

  // LEAK detection: Expected ASN not in detected list, but detected ASNs are typically upstream/customer
  if (!detectedAsns.includes(expectedAsn)) {
    const expectedIsSmall = expectedAsn > 64512 // Private ASN range
    const detectedArePrivate = detectedAsns.every(asn => asn > 64512)

    if (expectedIsSmall && detectedArePrivate) {
      return {
        hijack_type: 'LEAK',
        severity: 'MEDIUM',
        baseDescription: `Private ASN prefix leak: Expected ${expectedAsn}, detected ${detectedAsns.join(', ')}`
      }
    }

    // HIJACK: Completely unexpected ASN announcing prefix
    return {
      hijack_type: 'HIJACK',
      severity: prefixLength >= 24 ? 'CRITICAL' : 'HIGH', // Smaller prefixes more severe
      baseDescription: `Unauthorized ASN(s) detected: ${detectedAsns.join(', ')} announcing ${expectedAsn}'s prefix`
    }
  }

  // Default: Hijack with severity based on prefix specificity
  return {
    hijack_type: 'HIJACK',
    severity: prefixLength >= 24 ? 'CRITICAL' : 'HIGH',
    baseDescription: `Prefix hijack detected on ${prefix}`
  }
}

/**
 * Optional Ollama enrichment for CRITICAL severity hijacks
 * Falls back gracefully if Ollama is unavailable
 */
export async function enrichHijackDescriptionWithOllama(
  baseDescription: string,
  prefix: string,
  detectedAsns: number[]
): Promise<string> {
  try {
    const ollamaUrl = process.env.OLLAMA_URL || 'http://localhost:11434'
    const prompt = `You are a network security analyst. Provide a 1-2 sentence technical assessment of this BGP hijack:
- Prefix: ${prefix}
- Detected from ASN(s): ${detectedAsns.join(', ')}
- Initial assessment: ${baseDescription}

Focus on impact and recommended immediate actions.`

    const controller = new AbortController()
    const timeoutId = setTimeout(() => controller.abort(), 5000) // 5 second timeout

    const response = await fetch(`${ollamaUrl}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model: 'qwen2.5:3b',
        prompt,
        stream: false,
        temperature: 0.3
      }),
      signal: controller.signal
    })

    clearTimeout(timeoutId)

    if (!response.ok) {
      return baseDescription // Fallback to base description
    }

    const data = (await response.json()) as { response?: string }
    const enrichedText = data.response?.trim()

    // Only include AI Analysis if we got meaningful enrichment
    if (!enrichedText) {
      return baseDescription
    }

    return `${baseDescription}\n\nAI Analysis: ${enrichedText}`
  } catch (error) {
    // Graceful fallback: Ollama unavailable or timeout
    return baseDescription
  }
}

export async function checkForHijacks(asnPrefix: string, dbClient: HijackAlertsDatabaseClient): Promise<HijackDetectionResult[]> {
  const results: HijackDetectionResult[] = []

  // Parse ASN prefixes (e.g., "13335:185.1.0.0/24")
  const parts = asnPrefix.split(':')
  if (parts.length !== 2) {
    return [{ detected: false, reason: 'Invalid ASN:prefix format' }]
  }

  const [asnStr, prefix] = parts
  const asn = parseInt(asnStr)

  if (isNaN(asn)) {
    return [{ detected: false, reason: 'Invalid ASN number' }]
  }

  // Check if this hijack was recently detected (deduplicate)
  const recentEvent = await dbClient.getRecentHijackEvent(asn, prefix, 6)
  if (recentEvent) {
    return [{ detected: false, reason: 'Recently detected (within 6 hours), skipping to avoid spam' }]
  }

  // Simulate hijack detection (in production, integrate with bgp.he.net, RIPE Stat, etc.)
  const detectionResult = simulateHijackDetection(asn, prefix)

  if (detectionResult.detected && detectionResult.detected_asns) {
    // Deterministic classification
    const classification = classifyHijack(asn, detectionResult.detected_asns, prefix)

    // Optional Ollama enrichment for CRITICAL severity
    let finalDescription = classification.baseDescription
    if (classification.severity === 'CRITICAL') {
      finalDescription = await enrichHijackDescriptionWithOllama(
        classification.baseDescription,
        prefix,
        detectionResult.detected_asns
      )
    }

    results.push({
      detected: true,
      event: {
        asn,
        prefix,
        expected_asn: asn,
        detected_asns: detectionResult.detected_asns,
        hijack_type: classification.hijack_type,
        severity: classification.severity,
        description: finalDescription,
        details: { source: 'bgp_hijack_monitor', timestamp: new Date().toISOString() }
      }
    })
  } else {
    results.push({ detected: false, reason: 'No hijack detected' })
  }

  return results
}

interface DetectionSimulation {
  detected: boolean
  detected_asns?: number[]
}

function simulateHijackDetection(asn: number, prefix: string): DetectionSimulation {
  // Placeholder: in production, integrate with bgp.he.net, RIPE Stat, bgproutes.io, etc.
  // For now, return false (no hijack detected)
  return { detected: false }
}
