package handler

import (
	"context"
	"fmt"
	"net/http"
	"strings"
	"time"

	"cyberstrike-ai/internal/database"
	"cyberstrike-ai/internal/robot"
	"cyberstrike-ai/internal/security"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

type updateVulnerabilityAlertRequest struct {
	Enabled     bool   `json:"enabled"`
	MinSeverity string `json:"min_severity"`
}

func (h *VulnerabilityHandler) GetMyAlertSubscription(c *gin.Context) {
	session, ok := security.CurrentSession(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}
	sub, err := h.db.GetVulnerabilityAlertSubscription(session.UserID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	bindings, _ := h.db.ListRobotUserBindings(session.UserID)
	deliveryReady := false
	for _, binding := range bindings {
		if binding.Enabled && robot.SupportsProactive(binding.Platform) {
			deliveryReady = true
			break
		}
	}
	c.JSON(http.StatusOK, gin.H{"subscription": sub, "bindings": bindings, "delivery_ready": deliveryReady})
}

func (h *VulnerabilityHandler) UpdateMyAlertSubscription(c *gin.Context) {
	session, ok := security.CurrentSession(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}
	var req updateVulnerabilityAlertRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	sub, err := h.db.UpsertVulnerabilityAlertSubscription(session.UserID, req.Enabled, req.MinSeverity)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if h.audit != nil {
		h.audit.RecordOK(c, "vulnerability", "alert_subscription_update", "更新漏洞提醒订阅", "user", session.UserID, map[string]interface{}{
			"enabled": sub.Enabled, "min_severity": sub.MinSeverity,
		})
	}
	c.JSON(http.StatusOK, sub)
}

func vulnerabilityAlertSeverityLabel(value string) string {
	switch value {
	case "critical":
		return "严重"
	case "high":
		return "高危"
	case "medium":
		return "中危"
	case "low":
		return "低危"
	default:
		return "信息"
	}
}

func formatVulnerabilityRobotAlert(v *database.Vulnerability) string {
	return fmt.Sprintf("🚨 新漏洞提醒\n\n标题：%s\n严重程度：%s（%s）\n目标：%s\n影响：%s\n修复建议：%s\n漏洞 ID：%s\n\n请核实目标版本与实际暴露情况。",
		strings.TrimSpace(v.Title), vulnerabilityAlertSeverityLabel(v.Severity), v.Severity,
		fallbackAlertText(v.Target), fallbackAlertText(v.Impact), fallbackAlertText(v.Recommendation), v.ID)
}

func fallbackAlertText(value string) string {
	value = strings.TrimSpace(value)
	if value == "" {
		return "未填写"
	}
	if len([]rune(value)) > 300 {
		return string([]rune(value)[:300]) + "…"
	}
	return value
}

// NotifyNewVulnerability pushes an alert to every eligible bound robot identity.
// A failure on one platform never blocks vulnerability creation or other recipients.
func (h *RobotHandler) NotifyNewVulnerability(v *database.Vulnerability) {
	if h == nil || h.db == nil || v == nil {
		return
	}
	recipients, err := h.db.ListVulnerabilityAlertRecipients(v)
	if err != nil {
		h.logger.Warn("查询漏洞提醒接收人失败", zap.String("vulnerability_id", v.ID), zap.Error(err))
		return
	}
	eligible := recipients[:0]
	for _, recipient := range recipients {
		if robot.SupportsProactive(recipient.Platform) {
			eligible = append(eligible, recipient)
		}
	}
	if err := h.db.EnqueueVulnerabilityAlertDeliveries(v.ID, eligible); err != nil {
		h.logger.Warn("写入漏洞提醒投递队列失败", zap.String("vulnerability_id", v.ID), zap.Error(err))
		return
	}
	select {
	case h.alertWake <- struct{}{}:
	default:
	}
}

// RunVulnerabilityAlertWorker drains the durable outbox. Failed sends use
// exponential backoff and remain retryable across application restarts.
func (h *RobotHandler) RunVulnerabilityAlertWorker(ctx context.Context) {
	if h == nil || h.db == nil {
		return
	}
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()
	for {
		h.processVulnerabilityAlertDeliveries(ctx)
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
		case <-h.alertWake:
		}
	}
}

func (h *RobotHandler) processVulnerabilityAlertDeliveries(ctx context.Context) {
	deliveries, err := h.db.ListDueVulnerabilityAlertDeliveries(50)
	if err != nil {
		h.logger.Warn("读取漏洞提醒投递队列失败", zap.Error(err))
		return
	}
	for _, delivery := range deliveries {
		sendCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
		err := robot.SendProactive(sendCtx, h.config.Robots, delivery.Platform, delivery.ExternalUserID, formatVulnerabilityRobotAlert(delivery.Vulnerability))
		cancel()
		if err != nil {
			attempts := delivery.Attempts + 1
			_ = h.db.MarkVulnerabilityAlertDeliveryFailed(delivery.ID, attempts, err)
			h.logger.Warn("发送漏洞机器人提醒失败", zap.String("platform", delivery.Platform), zap.String("user_id", delivery.UserID), zap.String("vulnerability_id", delivery.Vulnerability.ID), zap.Int("attempt", attempts), zap.Error(err))
			continue
		}
		_ = h.db.MarkVulnerabilityAlertDeliverySent(delivery.ID)
		h.logger.Info("漏洞机器人提醒已发送", zap.String("platform", delivery.Platform), zap.String("user_id", delivery.UserID), zap.String("vulnerability_id", delivery.Vulnerability.ID))
	}
}

func (h *RobotHandler) cmdVulnerabilityAlerts(platform, externalUserID, arg string) string {
	access, err := h.resolveRobotAccess(platform, externalUserID)
	if err != nil {
		return h.robotAccessDeniedMessage(platform)
	}
	arg = strings.ToLower(strings.TrimSpace(arg))
	if arg == "" || arg == "status" || arg == "状态" {
		sub, err := h.db.GetVulnerabilityAlertSubscription(access.User.ID)
		if err != nil {
			return "读取漏洞提醒设置失败，请稍后重试。"
		}
		state := "已关闭"
		if sub.Enabled {
			state = "已开启"
		}
		return fmt.Sprintf("漏洞提醒%s；最低提醒级别：%s（%s）。\n可在 Web「漏洞管理」页面同步修改。", state, vulnerabilityAlertSeverityLabel(sub.MinSeverity), sub.MinSeverity)
	}
	enabled, severity := true, ""
	switch arg {
	case "开启", "开", "on", "enable":
		severity = "high"
	case "关闭", "关", "off", "disable":
		enabled, severity = false, "high"
	case "仅严重", "严重", "critical":
		severity = "critical"
	case "高危以上", "高危", "high":
		severity = "high"
	case "中危以上", "中危", "medium":
		severity = "medium"
	case "低危以上", "低危", "low":
		severity = "low"
	case "全部", "all", "info":
		severity = "info"
	default:
		return "用法：漏洞提醒 开启｜关闭｜仅严重｜高危以上｜中危以上"
	}
	current, _ := h.db.GetVulnerabilityAlertSubscription(access.User.ID)
	if (arg == "开启" || arg == "开" || arg == "on" || arg == "enable" || !enabled) && current != nil {
		severity = current.MinSeverity
	}
	sub, err := h.db.UpsertVulnerabilityAlertSubscription(access.User.ID, enabled, severity)
	if err != nil {
		return "更新漏洞提醒失败，请稍后重试。"
	}
	if !sub.Enabled {
		return "已关闭漏洞提醒。Web 端设置已同步。"
	}
	bindings, _ := h.db.ListRobotUserBindings(access.User.ID)
	deliveryReady := false
	for _, binding := range bindings {
		if binding.Enabled && robot.SupportsProactive(binding.Platform) {
			deliveryReady = true
			break
		}
	}
	if !deliveryReady {
		return fmt.Sprintf("已保存漏洞提醒：%s及以上。当前没有支持主动推送的已绑定账号；请绑定企业微信、飞书、Telegram、Slack 或 Discord。", vulnerabilityAlertSeverityLabel(sub.MinSeverity))
	}
	return fmt.Sprintf("已开启漏洞提醒：%s及以上漏洞将通过已绑定机器人推送。Web 端设置已同步。", vulnerabilityAlertSeverityLabel(sub.MinSeverity))
}
