#!/bin/sh
# SecuBox CVE Triage Agent
# Copyright (C) 2026 CyberMind.fr
#
# AI-powered CVE analysis and vulnerability management

CONFIG="cve-triage"
LIB_DIR="/usr/lib/cve-triage"
STATE_DIR="/var/lib/cve-triage"
CACHE_DIR="/var/cache/cve-triage"
LOG_TAG="cve-triage"

# Source libraries
. "$LIB_DIR/collector.sh"
. "$LIB_DIR/analyzer.sh"
. "$LIB_DIR/recommender.sh"
. "$LIB_DIR/applier.sh"

usage() {
	cat <<'EOF'
Usage: cve-triage <command> [options]

Commands:
  run             Run single triage cycle
  daemon          Run as background daemon
  status          Show agent status
  scan            Scan installed packages only
  fetch           Fetch latest CVE data
  analyze <cve>   Analyze specific CVE with AI

Recommendations:
  list-pending    List pending recommendations
  approve <id>    Approve recommendation
  reject <id>     Reject recommendation
  approve-all     Approve all pending
  clear-pending   Clear all pending

Alerts:
  alerts          Show active alerts
  ack <id>        Acknowledge alert

Reports:
  summary         Generate security summary
  export          Export CVE report (JSON)

Configuration: /etc/config/cve-triage
EOF
}

log_info() { logger -t "$LOG_TAG" "$*"; echo "[INFO] $*"; }
log_warn() { logger -t "$LOG_TAG" -p warning "$*"; echo "[WARN] $*" >&2; }
log_error() { logger -t "$LOG_TAG" -p err "$*"; echo "[ERROR] $*" >&2; }

uci_get() { uci -q get "${CONFIG}.$1"; }

load_config() {
	enabled=$(uci_get main.enabled)
	interval=$(uci_get main.interval)
	localai_url=$(uci_get main.localai_url)
	localai_model=$(uci_get main.localai_model)
	min_severity=$(uci_get main.min_severity)
	affected_only=$(uci_get main.affected_only)
	auto_apply_patches=$(uci_get main.auto_apply_patches)
	min_confidence=$(uci_get main.min_confidence)
	max_recommendations=$(uci_get main.max_recommendations)

	# Defaults
	[ -z "$interval" ] && interval=3600
	[ -z "$min_severity" ] && min_severity="high"
	[ -z "$affected_only" ] && affected_only=1
	[ -z "$min_confidence" ] && min_confidence=80
	[ -z "$max_recommendations" ] && max_recommendations=10

	mkdir -p "$STATE_DIR" "$CACHE_DIR"
}

# =============================================================================
# COMMANDS
# =============================================================================

cmd_status() {
	load_config
	echo "=== CVE Triage Agent Status ==="
	echo ""
	echo "Enabled: $([ "$enabled" = "1" ] && echo "Yes" || echo "No")"
	echo "Interval: ${interval}s ($(($interval / 60)) minutes)"
	echo "Min Severity: $min_severity"
	echo "Affected Only: $([ "$affected_only" = "1" ] && echo "Yes" || echo "No")"
	echo ""

	# Check LocalAI availability
	if check_localai; then
		echo "LocalAI: ONLINE ($localai_url)"
	else
		echo "LocalAI: OFFLINE (basic analysis mode)"
	fi
	echo ""

	# Package counts
	local opkg_count=$(opkg list-installed 2>/dev/null | wc -l)
	local lxc_count=$(ls -d /srv/lxc/*/ 2>/dev/null | wc -l)
	local docker_count=$(docker ps -q 2>/dev/null | wc -l)

	echo "Monitored Packages:"
	echo "  opkg: $opkg_count packages"
	echo "  LXC containers: $lxc_count"
	echo "  Docker containers: $docker_count"
	echo ""

	# Pending recommendations
	local pending=$(get_pending_count)
	echo "Pending Recommendations: $pending"

	# Active alerts
	local alerts=$(get_active_alerts | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
	echo "Active Alerts: $alerts"

	# Last run
	if [ -f "$STATE_DIR/last_run" ]; then
		echo ""
		echo "Last Run: $(cat "$STATE_DIR/last_run")"
	fi
}

cmd_scan() {
	load_config
	log_info "Scanning installed packages..."

	local packages=$(collect_all_packages)
	local pkg_count=$(echo "$packages" | jsonfilter -e '@.packages[*]' 2>/dev/null | wc -l)

	echo "Found $pkg_count packages"
	echo "$packages" > "$STATE_DIR/packages.json"

	# Show summary
	echo ""
	echo "Package sources:"
	echo "  opkg: $(echo "$packages" | jsonfilter -e '@.packages[*].source' 2>/dev/null | grep -c '^opkg$')"
	echo "  LXC: $(echo "$packages" | jsonfilter -e '@.packages[*].source' 2>/dev/null | grep -c '^lxc:')"
	echo "  Docker: $(echo "$packages" | jsonfilter -e '@.packages[*].source' 2>/dev/null | grep -c '^docker$')"
}

cmd_fetch() {
	load_config
	log_info "Fetching CVE data..."

	# Fetch NVD CVEs
	if [ "$(uci_get source.nvd.enabled)" = "1" ]; then
		local nvd_data=$(fetch_nvd_cves)
		local cve_count=$(echo "$nvd_data" | jsonfilter -e '@.totalResults' 2>/dev/null)
		echo "NVD: Found ${cve_count:-0} recent CVEs"
	fi

	# Fetch CrowdSec CVE alerts
	if [ "$(uci_get source.crowdsec_cve.enabled)" = "1" ]; then
		local cs_cves=$(collect_crowdsec_cves)
		local cs_count=$(echo "$cs_cves" | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
		echo "CrowdSec: Found $cs_count CVE-related alerts"
	fi
}

cmd_run() {
	load_config

	[ "$enabled" = "1" ] || {
		log_warn "CVE Triage agent is disabled"
		return 1
	}

	log_info "Starting CVE triage cycle..."

	# 1. Collect installed packages
	log_info "Collecting installed packages..."
	local packages=$(collect_all_packages)

	# 2. Fetch CVE data
	log_info "Fetching CVE data..."
	local nvd_data=$(fetch_nvd_cves)
	local nvd_cves=$(parse_nvd_cves "$nvd_data")

	# 3. Also get CrowdSec CVE alerts
	local cs_cves=$(collect_crowdsec_cves)

	# 4. Match CVEs to installed packages (if affected_only=1)
	local matched_cves="$nvd_cves"
	if [ "$affected_only" = "1" ]; then
		log_info "Matching CVEs to installed packages..."
		matched_cves=$(match_cves_to_packages "$nvd_cves" "$packages")
	fi

	# 5. Analyze CVEs
	local cve_count=$(echo "$matched_cves" | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
	log_info "Analyzing $cve_count CVEs..."
	local analyzed=$(analyze_cves_batch "$matched_cves")

	# 6. Generate recommendations
	log_info "Generating recommendations..."
	local recommendations=$(create_recommendations "$analyzed")
	save_recommendations "$recommendations"

	# 7. Process recommendations (queue/auto-apply)
	process_recommendations "$recommendations"
	auto_apply_recommendations "$recommendations"

	# 8. Generate summary
	local summary=$(generate_summary "$analyzed")
	echo "$summary" > "$STATE_DIR/last_summary.json"

	# Save last run timestamp
	date -Iseconds > "$STATE_DIR/last_run"

	# Report results
	local rec_count=$(echo "$recommendations" | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
	local pending=$(get_pending_count)

	echo ""
	echo "=== Triage Complete ==="
	echo "CVEs analyzed: $cve_count"
	echo "Recommendations: $rec_count"
	echo "Pending approval: $pending"
	echo ""

	# Show summary
	local risk_score=$(echo "$summary" | jsonfilter -e '@.risk_score' 2>/dev/null)
	local summary_text=$(echo "$summary" | jsonfilter -e '@.summary' 2>/dev/null)
	echo "Risk Score: ${risk_score:-N/A}/100"
	echo "Summary: ${summary_text:-Analysis complete}"
}

cmd_daemon() {
	load_config

	[ "$enabled" = "1" ] || {
		log_error "CVE Triage agent is disabled"
		exit 1
	}

	log_info "Starting CVE Triage daemon (interval: ${interval}s)..."

	while true; do
		cmd_run 2>&1 | while read -r line; do
			logger -t "$LOG_TAG" "$line"
		done

		sleep "$interval"
	done
}

cmd_analyze_cve() {
	local cve_id="$1"

	[ -z "$cve_id" ] && {
		echo "Usage: cve-triage analyze <CVE-ID>"
		exit 1
	}

	load_config

	log_info "Analyzing $cve_id..."

	# Try to fetch CVE details from NVD
	local nvd_url="https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=$cve_id"
	local nvd_data=$(wget -q -O - --timeout=30 "$nvd_url" 2>/dev/null)

	if [ -z "$nvd_data" ]; then
		log_warn "Could not fetch CVE details from NVD"
		return 1
	fi

	local cve_info=$(parse_nvd_cves "$nvd_data" | jsonfilter -e '@[0]' 2>/dev/null)

	if [ -z "$cve_info" ]; then
		log_error "CVE $cve_id not found"
		return 1
	fi

	local description=$(echo "$cve_info" | jsonfilter -e '@.description' 2>/dev/null)
	local cvss=$(echo "$cve_info" | jsonfilter -e '@.cvss' 2>/dev/null)
	local severity=$(echo "$cve_info" | jsonfilter -e '@.severity' 2>/dev/null)

	echo "=== $cve_id ==="
	echo "CVSS: $cvss ($severity)"
	echo "Description: $description"
	echo ""

	# Analyze with AI
	if check_localai; then
		log_info "Running AI analysis..."
		local analysis=$(analyze_cve "$cve_id" "$description" "$cvss" "")
		echo "=== AI Analysis ==="
		echo "$analysis" | jsonfilter -e '@' 2>/dev/null || echo "$analysis"
	else
		echo "LocalAI not available for detailed analysis"
	fi
}

cmd_list_pending() {
	load_config
	local pending=$(list_pending)
	local count=$(echo "$pending" | jsonfilter -e '@[*]' 2>/dev/null | wc -l)

	echo "=== Pending Recommendations ($count) ==="
	echo ""

	echo "$pending" | jsonfilter -e '@[*]' 2>/dev/null | while read -r rec; do
		local id=$(echo "$rec" | jsonfilter -e '@.id' 2>/dev/null)
		local cve=$(echo "$rec" | jsonfilter -e '@.cve' 2>/dev/null)
		local severity=$(echo "$rec" | jsonfilter -e '@.severity' 2>/dev/null)
		local action=$(echo "$rec" | jsonfilter -e '@.action' 2>/dev/null)
		local pkg=$(echo "$rec" | jsonfilter -e '@.affected_package' 2>/dev/null)

		echo "[$severity] $cve"
		echo "  ID: $id"
		echo "  Action: $action"
		echo "  Package: ${pkg:-unknown}"
		echo ""
	done
}

cmd_approve() {
	local rec_id="$1"
	[ -z "$rec_id" ] && {
		echo "Usage: cve-triage approve <recommendation-id>"
		exit 1
	}

	load_config
	approve_recommendation "$rec_id"
}

cmd_reject() {
	local rec_id="$1"
	local reason="$2"

	[ -z "$rec_id" ] && {
		echo "Usage: cve-triage reject <recommendation-id> [reason]"
		exit 1
	}

	load_config
	reject_recommendation "$rec_id" "$reason"
}

cmd_alerts() {
	load_config
	local alerts=$(get_active_alerts)
	local count=$(echo "$alerts" | jsonfilter -e '@[*]' 2>/dev/null | wc -l)

	echo "=== Active Alerts ($count) ==="
	echo ""

	echo "$alerts" | jsonfilter -e '@[*]' 2>/dev/null | while read -r alert; do
		local id=$(echo "$alert" | jsonfilter -e '@.id' 2>/dev/null)
		local cve=$(echo "$alert" | jsonfilter -e '@.cve' 2>/dev/null)
		local severity=$(echo "$alert" | jsonfilter -e '@.severity' 2>/dev/null)
		local message=$(echo "$alert" | jsonfilter -e '@.message' 2>/dev/null)
		local created=$(echo "$alert" | jsonfilter -e '@.created' 2>/dev/null)

		echo "[$severity] $cve - $created"
		echo "  ID: $id"
		echo "  $message"
		echo ""
	done
}

cmd_summary() {
	load_config

	if [ -f "$STATE_DIR/last_summary.json" ]; then
		local summary=$(cat "$STATE_DIR/last_summary.json")
		local risk=$(echo "$summary" | jsonfilter -e '@.risk_score' 2>/dev/null)
		local text=$(echo "$summary" | jsonfilter -e '@.summary' 2>/dev/null)

		echo "=== Security Summary ==="
		echo ""
		echo "Risk Score: ${risk:-N/A}/100"
		echo ""
		echo "$text"
	else
		echo "No summary available. Run 'cve-triage run' first."
	fi
}

cmd_export() {
	load_config

	local export_file="/tmp/cve-report-$(date +%Y%m%d).json"

	{
		echo '{'
		echo '"generated":"'"$(date -Iseconds)"'",'
		echo '"packages":'
		[ -f "$STATE_DIR/packages.json" ] && cat "$STATE_DIR/packages.json" || echo '[]'
		echo ','
		echo '"recommendations":'
		[ -f "$STATE_DIR/recommendations.json" ] && cat "$STATE_DIR/recommendations.json" || echo '[]'
		echo ','
		echo '"alerts":'
		[ -f "$STATE_DIR/alerts.json" ] && cat "$STATE_DIR/alerts.json" || echo '[]'
		echo ','
		echo '"summary":'
		[ -f "$STATE_DIR/last_summary.json" ] && cat "$STATE_DIR/last_summary.json" || echo '{}'
		echo '}'
	} > "$export_file"

	echo "Report exported to: $export_file"
}

# =============================================================================
# MAIN
# =============================================================================

case "$1" in
	run)
		cmd_run
		;;
	daemon)
		cmd_daemon
		;;
	status)
		cmd_status
		;;
	scan)
		cmd_scan
		;;
	fetch)
		cmd_fetch
		;;
	analyze)
		cmd_analyze_cve "$2"
		;;
	list-pending)
		cmd_list_pending
		;;
	approve)
		cmd_approve "$2"
		;;
	reject)
		cmd_reject "$2" "$3"
		;;
	approve-all)
		load_config
		approve_all
		;;
	clear-pending)
		load_config
		clear_pending
		;;
	alerts)
		cmd_alerts
		;;
	ack)
		# TODO: Acknowledge alert
		echo "Not implemented yet"
		;;
	summary)
		cmd_summary
		;;
	export)
		cmd_export
		;;
	-h|--help|help)
		usage
		;;
	*)
		usage
		exit 1
		;;
esac
