package main

import (
	"flag"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"dc-inspection/internal/alert"
	"dc-inspection/internal/config"
	"dc-inspection/internal/inspection"
	"dc-inspection/pkg/database"
)

func main() {
	configPath := flag.String("config", "configs/config.yaml", "配置文件路径")
	inspectOnly := flag.String("inspect", "all", "仅执行指定巡检: all/switch/cloud/ad/es")
	flag.Parse()

	// 设置日志格式
	log.SetOutput(os.Stdout)
	log.SetFlags(log.LstdFlags)

	// 加载配置
	cfg, err := config.Load(*configPath)
	if err != nil {
		log.Fatalf("加载配置失败: %v", err)
	}

	log.Printf("[INFO] ========== 机房一体化巡检工具启动 ==========")
	log.Printf("[INFO] 配置文件: %s", *configPath)
	log.Printf("[INFO] 最大并发: %d, 超时: %v", cfg.Global.MaxConcurrency, cfg.Global.Timeout)

	// 初始化数据库
	db, err := database.NewDB(cfg.MySQL.DSN(), cfg.MySQL.MaxOpenConns, cfg.MySQL.MaxIdleConns)
	if err != nil {
		log.Fatalf("数据库初始化失败: %v", err)
	}
	defer db.Close()

	if err := db.InitSchema(); err != nil {
		log.Fatalf("数据库表结构初始化失败: %v", err)
	}
	log.Printf("[INFO] 数据库初始化完成: %s:%d/%s", cfg.MySQL.Host, cfg.MySQL.Port, cfg.MySQL.Database)

	// 初始化告警器
	alerter := alert.NewWeChatAlert(cfg.Alert.WebhookURL, cfg.Alert.Enabled, cfg.Alert.DedupWindow)

	// 使用 channel 收集各模块巡检结果
	type moduleResult struct {
		name    string
		records []*database.InspectionRecord
		alerts  []string
	}

	resultChan := make(chan moduleResult, 4)
	var wg sync.WaitGroup

	shouldRun := func(name string) bool {
		return *inspectOnly == "all" || *inspectOnly == name
	}

	// ========== 1. 交换机 SSH 批量巡检 ==========
	if shouldRun("switch") {
		wg.Add(1)
		go func() {
			defer wg.Done()
			log.Printf("[INFO] >>> 开始交换机 SSH 批量巡检 (%d 台设备)", len(cfg.Switches.Devices))

			inspector := inspection.NewSwitchInspector(&cfg.Switches, cfg.Global.MaxConcurrency)
			metricsList := inspector.Inspect()

			var records []*database.InspectionRecord
			var allAlerts []string

			for _, metrics := range metricsList {
				rec := inspector.ToRecord(metrics)
				records = append(records, rec.ToDBRecord())
				allAlerts = append(allAlerts, inspector.CheckThresholds(metrics)...)
			}

			if err := db.SaveRecords(records); err != nil {
				log.Printf("[ERROR] 交换机巡检记录保存失败: %v", err)
			}

			log.Printf("[INFO] <<< 交换机巡检完成: %d 台设备, %d 条告警", len(metricsList), len(allAlerts))
			resultChan <- moduleResult{name: "switch", records: records, alerts: allAlerts}
		}()
	}

	// ========== 2. 云桌面资源指标采集 ==========
	if shouldRun("cloud") {
		wg.Add(1)
		go func() {
			defer wg.Done()
			log.Printf("[INFO] >>> 开始云桌面资源指标采集")

			inspector := inspection.NewCloudDesktopInspector(&cfg.CloudDesktop)
			poolMetrics := inspector.Inspect()

			var records []*database.InspectionRecord
			var allAlerts []string

			for _, pool := range poolMetrics {
				rec := inspector.ToRecord(pool)
				records = append(records, rec.ToDBRecord())
				allAlerts = append(allAlerts, inspector.CheckThresholds(pool)...)
			}

			if err := db.SaveRecords(records); err != nil {
				log.Printf("[ERROR] 云桌面巡检记录保存失败: %v", err)
			}

			log.Printf("[INFO] <<< 云桌面巡检完成: %d 个桌面池, %d 条告警", len(poolMetrics), len(allAlerts))
			resultChan <- moduleResult{name: "cloud_desktop", records: records, alerts: allAlerts}
		}()
	}

	// ========== 3. AD 域账号安全扫描 ==========
	if shouldRun("ad") {
		wg.Add(1)
		go func() {
			defer wg.Done()
			log.Printf("[INFO] >>> 开始 AD 域账号安全扫描")

			inspector := inspection.NewADSecurityInspector(&cfg.LDAP, &cfg.ADSecurity)
			report := inspector.Inspect()

			rec := inspector.ToRecord(report)
			records := []*database.InspectionRecord{rec.ToDBRecord()}

			if err := db.SaveRecords(records); err != nil {
				log.Printf("[ERROR] AD 安全扫描记录保存失败: %v", err)
			}

			alerts := inspector.CheckThresholds(report)
			log.Printf("[INFO] <<< AD 安全扫描完成: 账户 %d, 风险 %d, %d 条告警",
				report.TotalAccounts, len(report.RiskAccounts), len(alerts))
			resultChan <- moduleResult{name: "ad_security", records: records, alerts: alerts}
		}()
	}

	// ========== 4. ES 异常日志检索 ==========
	if shouldRun("es") {
		wg.Add(1)
		go func() {
			defer wg.Done()
			log.Printf("[INFO] >>> 开始 ES 异常日志检索")

			inspector := inspection.NewESLogInspector(&cfg.Elasticsearch)
			report := inspector.Inspect()

			rec := inspector.ToRecord(report)
			records := []*database.InspectionRecord{rec.ToDBRecord()}

			if err := db.SaveRecords(records); err != nil {
				log.Printf("[ERROR] ES 日志检索记录保存失败: %v", err)
			}

			alerts := inspector.CheckThresholds(report)
			log.Printf("[INFO] <<< ES 日志检索完成: 异常日志 %d, %d 条告警",
				report.TotalAbnormal, len(alerts))
			resultChan <- moduleResult{name: "es_log", records: records, alerts: alerts}
		}()
	}

	// 等待所有巡检完成
	go func() {
		wg.Wait()
		close(resultChan)
	}()

	// 收集结果并推送告警
	totalRecords := 0
	totalAlerts := 0
	var allAlertMessages []*alert.AlertMessage

	for result := range resultChan {
		totalRecords += len(result.records)
		totalAlerts += len(result.alerts)

		if len(result.alerts) > 0 {
			level := "warning"
			for _, rec := range result.records {
				if rec.Status == "critical" {
					level = "critical"
					break
				}
			}

			msg := &alert.AlertMessage{
				Type:    result.name,
				Target:  result.name,
				Level:   level,
				Title:   getModuleTitle(result.name),
				Content: strings.Join(result.alerts, "\n"),
				Time:    time.Now(),
			}
			allAlertMessages = append(allAlertMessages, msg)
		}
	}

	// 推送告警到企业微信
	if len(allAlertMessages) > 0 {
		log.Printf("[INFO] ========== 推送告警 (%d 条) ==========", len(allAlertMessages))
		errs := alerter.SendBatch(allAlertMessages)
		for _, e := range errs {
			log.Printf("[ERROR] %v", e)
		}
	} else {
		log.Printf("[INFO] 本次巡检无告警")
	}

	// 输出汇总报告
	log.Printf("[INFO] ========== 巡检汇总 ==========")
	log.Printf("[INFO] 巡检记录: %d 条", totalRecords)
	log.Printf("[INFO] 告警总数: %d 条", totalAlerts)
	log.Printf("[INFO] 推送告警: %d 条", len(allAlertMessages))
	log.Printf("[INFO] 巡检完成时间: %s", time.Now().Format("2006-01-02 15:04:05"))
	log.Printf("[INFO] ============================================")
}

// getModuleTitle 获取模块中文标题
func getModuleTitle(name string) string {
	titles := map[string]string{
		"switch":        "交换机巡检告警",
		"cloud_desktop": "云桌面资源告警",
		"ad_security":   "AD域账号安全告警",
		"es_log":        "ELK异常日志告警",
	}
	if title, ok := titles[name]; ok {
		return title
	}
	return "机房巡检告警"
}
