package api

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"clicd/internal/config"
)

// SecurityAlert represents a detected abuse event.
type SecurityAlert struct {
	ID            string `json:"id"`
	ContainerName string `json:"container_name"`
	Type          string `json:"type"`     // port_scan, horizontal_scan, brute_force, ddos, spam, malware, mining, proxy, reflection
	Severity      string `json:"severity"` // low, medium, high, critical
	SourceIP      string `json:"source_ip"`
	TargetIP      string `json:"target_ip"`
	TargetPort    int    `json:"target_port"`
	Detail        string `json:"detail"`
	LogLine       string `json:"log_line"`
	Timestamp     string `json:"timestamp"`
	Count         int    `json:"count"`
}

// SecurityScanner monitors container network activity for abuse patterns.
type SecurityScanner struct {
	mu        sync.Mutex
	alerts    []SecurityAlert
	nextID    int
	scanCount map[string]int
	stopChan  chan struct{}
}

type connEntry struct {
	dstIP   string
	dstPort int
	proto   string
	state   string
	line    string
}

type trafficStats struct {
	total           int
	totalSynSent    int
	destCounts      map[string]int
	destPorts       map[string]map[int]int
	portDestCounts  map[int]map[string]int
	portTotalCounts map[int]int
	udpDestCounts   map[int]map[string]int
	udpTotalCounts  map[int]int
	synSentByDst    map[string]int
}

var scanner *SecurityScanner
var scannerStarted bool

var bruteForcePorts = map[int]string{
	21:    "FTP",
	22:    "SSH",
	23:    "Telnet",
	135:   "MS-RPC",
	139:   "NetBIOS",
	445:   "SMB",
	3306:  "MySQL",
	3389:  "RDP",
	5432:  "PostgreSQL",
	5900:  "VNC",
	5901:  "VNC",
	5985:  "WinRM",
	5986:  "WinRM",
	6379:  "Redis",
	9200:  "Elasticsearch",
	27017: "MongoDB",
}

var smtpPorts = map[int]string{
	25:   "SMTP",
	465:  "SMTPS",
	587:  "SMTP submission",
	2525: "SMTP alternate",
}

var reflectionPorts = map[int]string{
	17:    "QOTD",
	19:    "Chargen",
	53:    "DNS",
	69:    "TFTP",
	111:   "Portmap",
	123:   "NTP",
	137:   "NetBIOS",
	161:   "SNMP",
	389:   "CLDAP",
	500:   "IKE",
	1900:  "SSDP",
	3702:  "WS-Discovery",
	4500:  "IPsec NAT-T",
	5353:  "mDNS",
	11211: "Memcached",
}

var miningPorts = map[int]string{
	3333:  "Stratum",
	3334:  "Stratum",
	3335:  "Stratum",
	4444:  "Stratum",
	5555:  "Stratum",
	7777:  "Stratum",
	8888:  "Stratum",
	9999:  "Stratum",
	14433: "Stratum",
	14444: "Stratum",
}

var proxyPorts = map[int]string{
	1080:  "SOCKS",
	3128:  "HTTP proxy",
	8118:  "Privoxy",
	9001:  "Tor OR",
	9030:  "Tor directory",
	9050:  "Tor SOCKS",
	1194:  "OpenVPN",
	51820: "WireGuard",
}

var malwarePorts = map[int]string{
	1337:  "common backdoor",
	31337: "Back Orifice",
	4444:  "Metasploit/reverse shell",
	5555:  "Android debug/reverse shell",
	6666:  "IRC botnet",
	6667:  "IRC botnet",
	6697:  "IRC over TLS",
	9050:  "Tor/C2 proxy",
}

func InitScanner() {
	if scannerStarted {
		return
	}
	scannerStarted = true
	scanner = newSecurityScanner()
	go scanner.monitorLoop()
}

func newSecurityScanner() *SecurityScanner {
	return &SecurityScanner{
		alerts:    make([]SecurityAlert, 0),
		scanCount: make(map[string]int),
		stopChan:  make(chan struct{}),
	}
}

func ensureScanner() *SecurityScanner {
	if scanner == nil {
		scanner = newSecurityScanner()
	}
	return scanner
}

func (ss *SecurityScanner) monitorLoop() {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ss.stopChan:
			return
		case <-ticker.C:
			ss.checkAllContainers()
		}
	}
}

func (ss *SecurityScanner) alertCount() int {
	ss.mu.Lock()
	defer ss.mu.Unlock()
	return len(ss.alerts)
}

func (ss *SecurityScanner) checkAllContainers() {
	for _, c := range config.AppConfig.Containers {
		if c.Status != "running" || c.IP == "" {
			continue
		}
		ss.checkContainer(c.Name, c.IP)
	}
}

func (ss *SecurityScanner) checkContainer(name, ip string) {
	lines := readConntrackLines(ip)
	if len(lines) == 0 {
		return
	}

	stats := newTrafficStats()
	for _, line := range lines {
		conn, ok := parseConntrackLine(line, ip)
		if !ok || conn.dstIP == "" || conn.dstIP == ip {
			continue
		}
		stats.add(conn)
	}

	if stats.total == 0 {
		return
	}

	alertBefore := ss.alertCount()
	ss.detectPortScans(name, ip, stats)
	ss.detectBruteForce(name, ip, stats)
	ss.detectSpam(name, ip, stats)
	ss.detectMassAbuse(name, ip, stats)
	ss.detectReflectionAbuse(name, ip, stats)
	ss.detectMining(name, ip, stats)
	ss.detectProxyAndTor(name, ip, stats)
	ss.detectMalware(name, ip, stats)

	// If new alerts were generated, snapshot the conntrack data for later retrieval.
	if ss.alertCount() > alertBefore {
		config.SaveConntrackSnapshot(ip, lines)
	}
}

func newTrafficStats() *trafficStats {
	return &trafficStats{
		destCounts:      make(map[string]int),
		destPorts:       make(map[string]map[int]int),
		portDestCounts:  make(map[int]map[string]int),
		portTotalCounts: make(map[int]int),
		udpDestCounts:   make(map[int]map[string]int),
		udpTotalCounts:  make(map[int]int),
		synSentByDst:    make(map[string]int),
	}
}

func (ts *trafficStats) add(conn connEntry) {
	ts.total++
	ts.destCounts[conn.dstIP]++

	if conn.dstPort > 0 {
		if ts.destPorts[conn.dstIP] == nil {
			ts.destPorts[conn.dstIP] = make(map[int]int)
		}
		ts.destPorts[conn.dstIP][conn.dstPort]++

		if ts.portDestCounts[conn.dstPort] == nil {
			ts.portDestCounts[conn.dstPort] = make(map[string]int)
		}
		ts.portDestCounts[conn.dstPort][conn.dstIP]++
		ts.portTotalCounts[conn.dstPort]++

		if conn.proto == "udp" {
			if ts.udpDestCounts[conn.dstPort] == nil {
				ts.udpDestCounts[conn.dstPort] = make(map[string]int)
			}
			ts.udpDestCounts[conn.dstPort][conn.dstIP]++
			ts.udpTotalCounts[conn.dstPort]++
		}
	}

	if conn.state == "SYN_SENT" {
		ts.totalSynSent++
		ts.synSentByDst[conn.dstIP]++
	}
}

func (ss *SecurityScanner) detectPortScans(name, ip string, stats *trafficStats) {
	for dstIP, portCounts := range stats.destPorts {
		uniquePorts := len(portCounts)
		switch {
		case uniquePorts >= 20:
			ss.addAlert(name, "port_scan", "high", ip, dstIP, 0,
				fmt.Sprintf("端口扫描: 同一目标 %s 出现 %d 个不同目标端口", dstIP, uniquePorts),
				"")
		case uniquePorts >= 8:
			ss.addAlert(name, "port_scan", "medium", ip, dstIP, 0,
				fmt.Sprintf("可疑端口探测: 同一目标 %s 出现 %d 个不同目标端口", dstIP, uniquePorts),
				"")
		}
	}

	for port, targets := range stats.portDestCounts {
		uniqueTargets := len(targets)
		if service, ok := bruteForcePorts[port]; ok {
			if uniqueTargets >= 30 {
				ss.addAlert(name, "brute_force", "critical", ip, "*", port,
					fmt.Sprintf("横向爆破: 目标服务 %s(%d) 覆盖 %d 个不同 IP", service, port, uniqueTargets),
					"")
			} else if uniqueTargets >= 10 {
				ss.addAlert(name, "brute_force", "high", ip, "*", port,
					fmt.Sprintf("疑似横向爆破: 目标服务 %s(%d) 覆盖 %d 个不同 IP", service, port, uniqueTargets),
					"")
			}
			continue
		}

		if uniqueTargets >= 40 {
			ss.addAlert(name, "horizontal_scan", "high", ip, "*", port,
				fmt.Sprintf("横向扫描: 同一端口 %d 覆盖 %d 个不同目标", port, uniqueTargets),
				"")
		} else if uniqueTargets >= 15 {
			ss.addAlert(name, "horizontal_scan", "medium", ip, "*", port,
				fmt.Sprintf("可疑横向探测: 同一端口 %d 覆盖 %d 个不同目标", port, uniqueTargets),
				"")
		}
	}
}

func (ss *SecurityScanner) detectBruteForce(name, ip string, stats *trafficStats) {
	for dstIP, portCounts := range stats.destPorts {
		for port, count := range portCounts {
			service, sensitive := bruteForcePorts[port]
			if !sensitive {
				continue
			}

			if count >= 20 {
				ss.addAlert(name, "brute_force", "critical", ip, dstIP, port,
					fmt.Sprintf("暴力破解: %s(%d) 当前连接数 %d", service, port, count),
					"")
			} else if count >= 10 {
				ss.addAlert(name, "brute_force", "high", ip, dstIP, port,
					fmt.Sprintf("疑似暴力破解: %s(%d) 当前连接数 %d", service, port, count),
					"")
			}
		}
	}
}

func (ss *SecurityScanner) detectSpam(name, ip string, stats *trafficStats) {
	total, targets := countPorts(stats.portTotalCounts, stats.portDestCounts, smtpPorts)
	if total == 0 {
		return
	}

	if targets >= 10 || total >= 30 {
		ss.addAlert(name, "spam", "critical", ip, "*", 25,
			fmt.Sprintf("疑似垃圾邮件: SMTP 相关端口当前连接 %d 条，覆盖 %d 个目标", total, targets),
			"")
	} else if targets >= 2 || total >= 5 {
		ss.addAlert(name, "spam", "high", ip, "*", 25,
			fmt.Sprintf("可疑邮件发送: SMTP 相关端口当前连接 %d 条，覆盖 %d 个目标", total, targets),
			"")
	}
}

func (ss *SecurityScanner) detectMassAbuse(name, ip string, stats *trafficStats) {
	targets := len(stats.destCounts)
	switch {
	case targets >= 100:
		ss.addAlert(name, "ddos", "critical", ip, "*", 0,
			fmt.Sprintf("大规模对外连接: 当前覆盖 %d 个不同目标", targets),
			"")
	case targets >= 35:
		ss.addAlert(name, "ddos", "high", ip, "*", 0,
			fmt.Sprintf("大量对外连接: 当前覆盖 %d 个不同目标", targets),
			"")
	}

	switch {
	case stats.total >= 500:
		ss.addAlert(name, "ddos", "critical", ip, "*", 0,
			fmt.Sprintf("异常大量连接: 当前 conntrack 出站记录 %d 条", stats.total),
			"")
	case stats.total >= 200:
		ss.addAlert(name, "ddos", "high", ip, "*", 0,
			fmt.Sprintf("高连接数: 当前 conntrack 出站记录 %d 条", stats.total),
			"")
	}

	if stats.totalSynSent >= 100 {
		ss.addAlert(name, "ddos", "critical", ip, "*", 0,
			fmt.Sprintf("大量半开连接: 当前 SYN_SENT %d 条", stats.totalSynSent),
			"")
	}

	for dstIP, count := range stats.synSentByDst {
		if count >= 50 {
			ss.addAlert(name, "ddos", "critical", ip, dstIP, 0,
				fmt.Sprintf("SYN 洪水: 单一目标半开连接 %d 条", count),
				"")
		} else if count >= 20 {
			ss.addAlert(name, "ddos", "high", ip, dstIP, 0,
				fmt.Sprintf("可疑 SYN 洪水: 单一目标半开连接 %d 条", count),
				"")
		}
	}
}

func (ss *SecurityScanner) detectReflectionAbuse(name, ip string, stats *trafficStats) {
	for port, service := range reflectionPorts {
		total := stats.udpTotalCounts[port]
		targets := len(stats.udpDestCounts[port])
		if total == 0 {
			continue
		}

		if targets >= 30 || total >= 100 {
			ss.addAlert(name, "reflection", "critical", ip, "*", port,
				fmt.Sprintf("UDP 反射放大: %s(%d) 当前 UDP 连接 %d 条，覆盖 %d 个目标", service, port, total, targets),
				"")
		} else if targets >= 10 || total >= 30 {
			ss.addAlert(name, "reflection", "high", ip, "*", port,
				fmt.Sprintf("疑似 UDP 反射放大: %s(%d) 当前 UDP 连接 %d 条，覆盖 %d 个目标", service, port, total, targets),
				"")
		}
	}
}

func (ss *SecurityScanner) detectMining(name, ip string, stats *trafficStats) {
	for port, service := range miningPorts {
		total := stats.portTotalCounts[port]
		if total == 0 {
			continue
		}

		severity := "high"
		if total >= 5 {
			severity = "critical"
		}
		ss.addAlert(name, "mining", severity, ip, "*", port,
			fmt.Sprintf("疑似挖矿连接: %s/%d 当前连接 %d 条", service, port, total),
			"")
	}
}

func (ss *SecurityScanner) detectProxyAndTor(name, ip string, stats *trafficStats) {
	for port, service := range proxyPorts {
		total := stats.portTotalCounts[port]
		targets := len(stats.portDestCounts[port])
		if total == 0 {
			continue
		}

		if port == 1194 || port == 51820 {
			if targets < 3 && total < 10 {
				continue
			}
		}

		severity := "high"
		if targets >= 10 || total >= 30 {
			severity = "critical"
		}
		ss.addAlert(name, "proxy", severity, ip, "*", port,
			fmt.Sprintf("疑似代理/VPN/Tor 滥用: %s(%d) 当前连接 %d 条，覆盖 %d 个目标", service, port, total, targets),
			"")
	}

	total8080 := stats.portTotalCounts[8080]
	targets8080 := len(stats.portDestCounts[8080])
	if targets8080 >= 5 || total8080 >= 20 {
		ss.addAlert(name, "proxy", "high", ip, "*", 8080,
			fmt.Sprintf("疑似开放代理流量: HTTP 代理常用端口 8080 当前连接 %d 条，覆盖 %d 个目标", total8080, targets8080),
			"")
	}
}

func (ss *SecurityScanner) detectMalware(name, ip string, stats *trafficStats) {
	for port, label := range malwarePorts {
		total := stats.portTotalCounts[port]
		if total == 0 {
			continue
		}

		ss.addAlert(name, "malware", "critical", ip, "*", port,
			fmt.Sprintf("疑似恶意软件/C2 连接: %s 端口 %d 当前连接 %d 条", label, port, total),
			"")
	}
}

func readConntrackLines(ip string) []string {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	cmd := exec.CommandContext(ctx, "conntrack", "-L", "-s", ip)
	output, err := cmd.Output()
	if err == nil && len(output) > 0 {
		return splitNonEmptyLines(string(output))
	}

	var lines []string
	for _, path := range []string{"/proc/net/nf_conntrack", "/proc/net/ip_conntrack"} {
		data, readErr := os.ReadFile(path)
		if readErr != nil {
			continue
		}
		for _, line := range strings.Split(string(data), "\n") {
			line = strings.TrimSpace(line)
			if line == "" {
				continue
			}
			if strings.Contains(line, "src="+ip+" ") {
				lines = append(lines, line)
			}
		}
	}
	return lines
}

func splitNonEmptyLines(raw string) []string {
	lines := make([]string, 0)
	for _, line := range strings.Split(raw, "\n") {
		line = strings.TrimSpace(line)
		if line != "" {
			lines = append(lines, line)
		}
	}
	return lines
}

func parseConntrackLine(line, containerIP string) (connEntry, bool) {
	srcIP := extractField(line, "src=")
	if srcIP != containerIP {
		return connEntry{}, false
	}

	dstIP := extractField(line, "dst=")
	dstPort, _ := strconv.Atoi(extractField(line, "dport="))

	return connEntry{
		dstIP:   dstIP,
		dstPort: dstPort,
		proto:   extractProtocol(line),
		state:   extractConnState(line),
		line:    line,
	}, true
}

func extractProtocol(line string) string {
	for _, field := range strings.Fields(line) {
		switch field {
		case "tcp", "udp", "icmp", "icmpv6", "sctp":
			return field
		}
	}
	return ""
}

func extractConnState(line string) string {
	for _, field := range strings.Fields(line) {
		switch field {
		case "SYN_SENT", "SYN_RECV", "ESTABLISHED", "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "FIN_WAIT", "LAST_ACK", "UNREPLIED":
			return field
		}
	}
	return ""
}

func countPorts(totalCounts map[int]int, destCounts map[int]map[string]int, ports map[int]string) (int, int) {
	total := 0
	targets := make(map[string]struct{})
	for port := range ports {
		total += totalCounts[port]
		for dstIP := range destCounts[port] {
			targets[dstIP] = struct{}{}
		}
	}
	return total, len(targets)
}

func (ss *SecurityScanner) addAlert(name, alertType, severity, srcIP, dstIP string, port int, detail, logLine string) {
	ss.mu.Lock()

	now := time.Now()
	cutoff := now.Add(-5 * time.Minute)
	shouldShutdown := false

	for i := range ss.alerts {
		a := &ss.alerts[i]
		if a.ContainerName != name || a.Type != alertType || a.TargetIP != dstIP || a.TargetPort != port {
			continue
		}
		t, err := time.Parse("2006-01-02 15:04:05", a.Timestamp)
		if err != nil || t.Before(cutoff) {
			continue
		}

		a.Count++
		a.Detail = detail
		a.LogLine = logLine
		a.Timestamp = now.Format("2006-01-02 15:04:05")
		if severityRank(severity) > severityRank(a.Severity) {
			a.Severity = severity
		}
		shouldShutdown = config.AppConfig.SecurityAutoShutdown
		ss.mu.Unlock()
		if shouldShutdown {
			autoShutdownAlertContainer(name, alertType, severity)
		}
		return
	}

	ss.nextID++
	alert := SecurityAlert{
		ID:            fmt.Sprintf("alert-%d", ss.nextID),
		ContainerName: name,
		Type:          alertType,
		Severity:      severity,
		SourceIP:      srcIP,
		TargetIP:      dstIP,
		TargetPort:    port,
		Detail:        detail,
		LogLine:       logLine,
		Timestamp:     now.Format("2006-01-02 15:04:05"),
		Count:         1,
	}

	ss.alerts = append(ss.alerts, alert)
	config.AddAuditLog("security_"+alertType, name, fmt.Sprintf("[%s] %s", severity, detail), "system")
	shouldShutdown = config.AppConfig.SecurityAutoShutdown

	if len(ss.alerts) > 200 {
		ss.alerts = ss.alerts[len(ss.alerts)-200:]
	}
	ss.mu.Unlock()

	if shouldShutdown {
		autoShutdownAlertContainer(name, alertType, severity)
	}
}

func severityRank(severity string) int {
	switch severity {
	case "critical":
		return 4
	case "high":
		return 3
	case "medium":
		return 2
	case "low":
		return 1
	default:
		return 0
	}
}

func autoShutdownAlertContainer(containerName, alertType, severity string) {
	c := config.FindContainerByName(containerName)
	if c == nil || c.Status != "running" {
		return
	}
	reason := fmt.Sprintf("%s 告警触发策略临时封禁", alertType)
	if severity != "" {
		reason = fmt.Sprintf("[%s] %s", severity, reason)
	}
	config.SetContainerPolicyBlock(c.ID, true, reason)
	taskID, queued := globalQueue.EnqueueSecurityStop(c.ID, c.Name)
	if queued {
		config.AddAuditLog("security_auto_shutdown", c.Name, fmt.Sprintf("[%s] %s 告警触发自动关机任务 %s", severity, alertType, taskID), "system")
	}
}

// HandleSecurityAlerts returns all security alerts.
func HandleSecurityAlerts(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		jsonResponse(w, http.StatusMethodNotAllowed, APIResponse{Success: false, Message: "Method not allowed"})
		return
	}
	if !requireScope(w, r, "security:read") {
		return
	}

	jsonResponse(w, http.StatusOK, APIResponse{Success: true, Data: filterSecurityAlertsForRequest(r, mergedSecurityAlerts())})
}

// HandleSecuritySettings returns or updates security automation settings.
func HandleSecuritySettings(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		if !requireScope(w, r, "security:read") {
			return
		}
		jsonResponse(w, http.StatusOK, APIResponse{Success: true, Data: map[string]bool{
			"auto_shutdown": config.AppConfig.SecurityAutoShutdown,
		}})
	case http.MethodPut:
		if !requireScope(w, r, "security:settings") {
			return
		}
		var req struct {
			AutoShutdown bool `json:"auto_shutdown"`
		}
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid request body"})
			return
		}
		config.AppConfig.SecurityAutoShutdown = req.AutoShutdown
		if err := config.SaveConfig(); err != nil {
			jsonResponse(w, http.StatusInternalServerError, APIResponse{Success: false, Message: err.Error()})
			return
		}
		auditRequest(r, "security.settings", "auto_shutdown", fmt.Sprintf("auto_shutdown=%v", req.AutoShutdown), true, "")
		jsonResponse(w, http.StatusOK, APIResponse{Success: true, Data: map[string]bool{
			"auto_shutdown": config.AppConfig.SecurityAutoShutdown,
		}})
	default:
		jsonResponse(w, http.StatusMethodNotAllowed, APIResponse{Success: false, Message: "Method not allowed"})
	}
}

// HandleSecurityCheck triggers immediate security check for a container.
func HandleSecurityCheck(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		jsonResponse(w, http.StatusMethodNotAllowed, APIResponse{Success: false, Message: "Method not allowed"})
		return
	}
	if !requireScope(w, r, "security:check") {
		return
	}

	var req struct {
		ContainerName string `json:"container_name"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid request body"})
		return
	}

	c := config.FindContainerByName(req.ContainerName)
	if c == nil || c.IP == "" {
		jsonResponse(w, http.StatusNotFound, APIResponse{Success: false, Message: "Container not found or not running"})
		return
	}
	if !isContainerAllowedForRequest(r, c.UUID) {
		jsonResponse(w, http.StatusForbidden, APIResponse{Success: false, Message: "Access denied to this container"})
		return
	}

	ensureScanner().checkContainer(c.Name, c.IP)
	jsonResponse(w, http.StatusOK, APIResponse{Success: true, Message: "Security check completed"})
}

// HandleSecurityLogs returns connection logs for a container.
func HandleSecurityLogs(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		jsonResponse(w, http.StatusMethodNotAllowed, APIResponse{Success: false, Message: "Method not allowed"})
		return
	}
	if !requireScope(w, r, "security:read") {
		return
	}

	containerName := r.URL.Query().Get("container")
	if containerName == "" {
		jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Container name required"})
		return
	}

	c := config.FindContainerByName(containerName)
	if c == nil || c.IP == "" {
		jsonResponse(w, http.StatusOK, APIResponse{Success: true, Data: []map[string]interface{}{}})
		return
	}
	if !isContainerAllowedForRequest(r, c.UUID) {
		jsonResponse(w, http.StatusForbidden, APIResponse{Success: false, Message: "Access denied to this container"})
		return
	}

	jsonResponse(w, http.StatusOK, APIResponse{Success: true, Data: getConnectionLogs(c.IP)})
}

func getConnectionLogs(ip string) []map[string]interface{} {
	logs := make([]map[string]interface{}, 0)
	seen := map[string]bool{}

	parseLine := func(line string) map[string]interface{} {
		srcIP := extractField(line, "src=")
		dstIP := extractField(line, "dst=")
		srcPort := extractField(line, "sport=")
		dstPort := extractField(line, "dport=")
		sPort, _ := strconv.Atoi(srcPort)
		dPort, _ := strconv.Atoi(dstPort)
		return map[string]interface{}{
			"src_ip":   srcIP,
			"dst_ip":   dstIP,
			"src_port": sPort,
			"dst_port": dPort,
			"protocol": extractProtocol(line),
			"state":    extractConnState(line),
		}
	}

	// First, load stored snapshots from database (persisted at alert time).
	for _, line := range config.GetConntrackSnapshotLines(ip) {
		if len(logs) >= 100 {
			break
		}
		key := strings.TrimSpace(line)
		if key == "" || seen[key] {
			continue
		}
		seen[key] = true
		logs = append(logs, parseLine(line))
	}

	// Then, merge live conntrack data (deduplicated).
	for _, line := range readConntrackLines(ip) {
		if len(logs) >= 100 {
			break
		}
		key := strings.TrimSpace(line)
		if key == "" || seen[key] {
			continue
		}
		seen[key] = true
		logs = append(logs, parseLine(line))
	}

	return logs
}

func extractField(line, prefix string) string {
	idx := strings.Index(line, prefix)
	if idx == -1 {
		return ""
	}
	start := idx + len(prefix)
	end := start
	for end < len(line) && line[end] != ' ' && line[end] != '\t' {
		end++
	}
	return line[start:end]
}

// HandleContainerSecuritySummary returns security status for dashboard.
func HandleContainerSecuritySummary(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		jsonResponse(w, http.StatusMethodNotAllowed, APIResponse{Success: false, Message: "Method not allowed"})
		return
	}
	if !requireScope(w, r, "security:read") {
		return
	}

	critical := 0
	high := 0
	medium := 0
	low := 0
	alerts := filterSecurityAlertsForRequest(r, mergedSecurityAlerts())
	for _, a := range alerts {
		switch a.Severity {
		case "critical":
			critical++
		case "high":
			high++
		case "medium":
			medium++
		case "low":
			low++
		}
	}
	total := len(alerts)

	summary := map[string]interface{}{
		"total_alerts": total,
		"critical":     critical,
		"high":         high,
		"medium":       medium,
		"low":          low,
	}

	jsonResponse(w, http.StatusOK, APIResponse{Success: true, Data: summary})
}

func filterSecurityAlertsForRequest(r *http.Request, alerts []SecurityAlert) []SecurityAlert {
	allowed, restricted := requestAllowedContainers(r)
	if !restricted {
		return alerts
	}
	filtered := make([]SecurityAlert, 0, len(alerts))
	for _, alert := range alerts {
		if c := config.FindContainerByName(alert.ContainerName); c != nil && isContainerAllowed(allowed, c) {
			filtered = append(filtered, alert)
		}
	}
	return filtered
}

func mergedSecurityAlerts() []SecurityAlert {
	ss := ensureScanner()
	ss.mu.Lock()
	alerts := make([]SecurityAlert, len(ss.alerts))
	copy(alerts, ss.alerts)
	ss.mu.Unlock()

	seen := make(map[string]bool)
	for _, alert := range alerts {
		seen[securityAlertKey(alert)] = true
	}

	for i, log := range config.AppConfig.AuditLogs {
		alert, ok := alertFromSecurityAuditLog(log, i)
		if !ok {
			continue
		}
		key := securityAlertKey(alert)
		if seen[key] {
			continue
		}
		seen[key] = true
		alerts = append(alerts, alert)
	}

	sort.SliceStable(alerts, func(i, j int) bool {
		ti, errI := time.Parse("2006-01-02 15:04:05", alerts[i].Timestamp)
		tj, errJ := time.Parse("2006-01-02 15:04:05", alerts[j].Timestamp)
		if errI == nil && errJ == nil && !ti.Equal(tj) {
			return ti.After(tj)
		}
		return alerts[i].Timestamp > alerts[j].Timestamp
	})

	if len(alerts) > 200 {
		alerts = alerts[:200]
	}
	if alerts == nil {
		return []SecurityAlert{}
	}
	return alerts
}

func securityAlertKey(alert SecurityAlert) string {
	return strings.Join([]string{
		alert.Timestamp,
		alert.ContainerName,
		alert.Type,
		alert.Detail,
		strconv.Itoa(alert.TargetPort),
	}, "\x1f")
}

func alertFromSecurityAuditLog(log config.AuditLog, index int) (SecurityAlert, bool) {
	if !strings.HasPrefix(log.Action, "security_") || log.Action == "security_auto_shutdown" || log.Action == "security_policy_unblock" {
		return SecurityAlert{}, false
	}
	alertType := strings.TrimPrefix(log.Action, "security_")
	severity, detail := parseSecurityAuditDetail(log.Detail)
	targetPort := parseDetailPort(detail)

	targetIP := ""
	if targetPort > 0 || alertType == "horizontal_scan" || alertType == "brute_force" {
		targetIP = "*"
	}

	return SecurityAlert{
		ID:            fmt.Sprintf("audit-security-%d", index),
		ContainerName: log.Target,
		Type:          alertType,
		Severity:      severity,
		SourceIP:      "",
		TargetIP:      targetIP,
		TargetPort:    targetPort,
		Detail:        detail,
		LogLine:       "",
		Timestamp:     log.Time,
		Count:         1,
	}, true
}

func parseSecurityAuditDetail(detail string) (string, string) {
	severity := "medium"
	if strings.HasPrefix(detail, "[") {
		if end := strings.Index(detail, "]"); end > 1 {
			severity = detail[1:end]
			detail = strings.TrimSpace(detail[end+1:])
		}
	}
	return severity, detail
}

func parseDetailPort(detail string) int {
	for _, marker := range []string{"端口 ", "端口"} {
		idx := strings.Index(detail, marker)
		if idx == -1 {
			continue
		}
		start := idx + len(marker)
		for start < len(detail) && (detail[start] == ' ' || detail[start] == ':' || detail[start] == '(') {
			start++
		}
		end := start
		for end < len(detail) && detail[end] >= '0' && detail[end] <= '9' {
			end++
		}
		if end > start {
			port, _ := strconv.Atoi(detail[start:end])
			return port
		}
	}
	return 0
}
