package main

import (
	"bytes"
	"crypto/md5"
	"crypto/tls"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"math"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/gorilla/websocket"
	"github.com/shirou/gopsutil/v3/cpu"
	"github.com/shirou/gopsutil/v3/host"
)

// ==========================================
// 全局配置变量 (由命令行参数填充)
// ==========================================

var (
	IkuaiBaseURL      string
	IkuaiUser         string
	IkuaiPwd          string
	IkuaiTimeout      time.Duration
	KomariEndpoint    string
	KomariToken       string
	WebsocketInterval float64
	BasicInfoInterval int
	IgnoreUnsafeCert  bool
)

// ==========================================
// 辅助函数：强力数据清洗
// ==========================================

func safeInt64(v interface{}) int64 {
	if v == nil {
		return 0
	}
	switch val := v.(type) {
	case float64:
		if math.IsNaN(val) || math.IsInf(val, 0) {
			return 0
		}
		return int64(val)
	case int:
		return int64(val)
	case int64:
		return val
	case uint64:
		return int64(val)
	case string:
		// 移除除了数字和小数点以外的字符
		reg := regexp.MustCompile(`[^\d\.]`)
		cleanVal := reg.ReplaceAllString(val, "")
		if cleanVal == "" {
			return 0
		}
		if f, err := strconv.ParseFloat(cleanVal, 64); err == nil {
			return int64(f)
		}
	}
	return 0
}

func safeFloat64(v interface{}) float64 {
	if v == nil {
		return 0.0
	}
	switch val := v.(type) {
	case float64:
		if math.IsNaN(val) || math.IsInf(val, 0) {
			return 0.0
		}
		return val
	case int:
		return float64(val)
	case int64:
		return float64(val)
	case string:
		reg := regexp.MustCompile(`[^\d\.]`)
		cleanVal := reg.ReplaceAllString(val, "")
		if cleanVal == "" {
			return 0.0
		}
		if f, err := strconv.ParseFloat(cleanVal, 64); err == nil {
			return f
		}
	}
	return 0.0
}

// ==========================================
// 数据结构定义 (严格匹配 WS 协议)
// ==========================================

// BasicInfoPayload 基础信息上报结构
type BasicInfoPayload struct {
	Arch           string `json:"arch"`
	CpuCores       uint64 `json:"cpu_cores"`
	CpuName        string `json:"cpu_name"`
	DiskTotal      uint64 `json:"disk_total"`
	GpuName        string `json:"gpu_name"`
	Ipv4           string `json:"ipv4"`
	Ipv6           string `json:"ipv6"`
	MemTotal       uint64 `json:"mem_total"`
	Os             string `json:"os"`
	KernelVersion  string `json:"kernel_version"`
	SwapTotal      uint64 `json:"swap_total"`
	Version        string `json:"version"`
	Virtualization string `json:"virtualization"`
}

// MonitorPayload 实时监控数据结构
type MonitorPayload struct {
	Cpu         CpuStats  `json:"cpu"`
	Ram         RamStats  `json:"ram"`
	Swap        SwapStats `json:"swap"`
	Load        LoadStats `json:"load"`
	Disk        DiskStats `json:"disk"`
	Network     NetStats  `json:"network"`
	Connections ConnStats `json:"connections"`
	Uptime      int64     `json:"uptime"`
	Process     int64     `json:"process"`
	Message     string    `json:"message"`
}

type CpuStats struct {
	Usage float64 `json:"usage"`
}
type RamStats struct {
	Total int64 `json:"total"`
	Used  int64 `json:"used"`
}
type SwapStats struct {
	Total int64 `json:"total"`
	Used  int64 `json:"used"`
}
type LoadStats struct {
	Load1  float64 `json:"load1"`
	Load5  float64 `json:"load5"`
	Load15 float64 `json:"load15"`
}
type DiskStats struct {
	Total int64 `json:"total"`
	Used  int64 `json:"used"`
}
type NetStats struct {
	Up        int64 `json:"up"`
	Down      int64 `json:"down"`
	TotalUp   int64 `json:"totalUp"`
	TotalDown int64 `json:"totalDown"`
}
type ConnStats struct {
	Tcp int64 `json:"tcp"`
	Udp int64 `json:"udp"`
}

// ==========================================
// Ikuai客户端实现
// ==========================================

type IkuaiClient struct {
	BaseURL    string
	Username   string
	Password   string
	Timeout    time.Duration
	Client     *http.Client
	IsLoggedIn bool
	LoginURL   string
	ActionURL  string
	mu         sync.Mutex
}

func NewIkuaiClient() *IkuaiClient {
	jar, _ := cookiejar.New(nil)
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: IgnoreUnsafeCert},
	}
	
	baseURL := strings.TrimRight(IkuaiBaseURL, "/")

	client := &IkuaiClient{
		BaseURL:  baseURL,
		Username: IkuaiUser,
		Password: IkuaiPwd,
		Timeout:  IkuaiTimeout,
		Client: &http.Client{
			Jar:       jar,
			Timeout:   IkuaiTimeout,
			Transport: tr,
		},
	}
	client.ActionURL = client.BaseURL + "/Action/call"
	client.LoginURL = client.BaseURL + "/Action/login"
	return client
}

func (c *IkuaiClient) processPassword(password string) (string, string) {
	hasher := md5.New()
	hasher.Write([]byte(password))
	md5Hash := hex.EncodeToString(hasher.Sum(nil))
	salted := "salt_11" + password
	base64Encoded := base64.StdEncoding.EncodeToString([]byte(salted))
	return md5Hash, base64Encoded
}

func (c *IkuaiClient) Login() bool {
	c.mu.Lock()
	defer c.mu.Unlock()

	md5Hash, base64Encoded := c.processPassword(c.Password)
	payload := map[string]interface{}{
		"username":          c.Username,
		"passwd":            md5Hash,
		"pass":              base64Encoded,
		"remember_password": "true",
	}

	jsonPayload, _ := json.Marshal(payload)
	resp, err := c.Client.Post(c.LoginURL, "application/json", bytes.NewBuffer(jsonPayload))
	if err != nil {
		log.Printf("登录请求错误: %v", err)
		return false
	}
	defer resp.Body.Close()

	if resp.StatusCode == 200 {
		var result map[string]interface{}
		if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
			if !strings.Contains(strings.ToLower(resp.Request.URL.String()), "login") {
				c.IsLoggedIn = true
				return true
			}
			return false
		}
		if resCode, ok := result["Result"].(float64); ok && int(resCode) == 10000 {
			c.IsLoggedIn = true
			return true
		}
	}
	return false
}

func (c *IkuaiClient) CallAPI(funcName string, action string, params map[string]interface{}) map[string]interface{} {
	if !c.IsLoggedIn {
		if !c.Login() {
			return nil
		}
	}
	payload := map[string]interface{}{"func_name": funcName, "action": action}
	if params != nil {
		payload["param"] = params
	}

	jsonPayload, _ := json.Marshal(payload)
	resp, err := c.Client.Post(c.ActionURL, "application/json", bytes.NewBuffer(jsonPayload))
	if err != nil {
		return nil
	}
	defer resp.Body.Close()

	if resp.StatusCode == 200 {
		var data map[string]interface{}
		if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
			return nil
		}
		if resCode, ok := data["Result"].(float64); ok {
			if int(resCode) == 30000 {
				return data
			} else if int(resCode) == 10014 {
				c.IsLoggedIn = false
				c.Client.Jar, _ = cookiejar.New(nil)
				if c.Login() {
					return c.CallAPI(funcName, action, params)
				}
			}
		}
	}
	return nil
}

func getMap(data map[string]interface{}, keys ...string) map[string]interface{} {
	current := data
	for _, key := range keys {
		if val, ok := current[key].(map[string]interface{}); ok {
			current = val
		} else {
			return map[string]interface{}{}
		}
	}
	return current
}

func (c *IkuaiClient) GetHomepageStats() map[string]interface{} {
	res := c.CallAPI("homepage", "show", map[string]interface{}{"TYPE": "sysstat,ac_status"})
	if res != nil {
		if data, ok := res["Data"].(map[string]interface{}); ok {
			return data
		}
	}
	return nil
}

func (c *IkuaiClient) GetSystemStats() map[string]interface{} {
	res := c.CallAPI("sysstat", "show", map[string]interface{}{"TYPE": "verinfo,cpu,memory,stream,cputemp"})
	if res != nil {
		if data, ok := res["Data"].(map[string]interface{}); ok {
			if sys, ok := data["sysstat"].(map[string]interface{}); ok {
				return sys
			}
			return data
		}
	}
	return nil
}

func (c *IkuaiClient) GetWanNetworkStats() map[string]interface{} {
	res := c.CallAPI("monitor_iface", "show", map[string]interface{}{"TYPE": "iface_check,iface_stream"})
	if res == nil {
		return nil
	}
	data, ok := res["Data"].(map[string]interface{})
	if !ok {
		return nil
	}
	if ifaceStream, ok := data["iface_stream"].([]interface{}); ok {
		for _, item := range ifaceStream {
			iface := item.(map[string]interface{})
			if name, ok := iface["interface"].(string); ok && strings.HasPrefix(name, "wan") {
				return iface
			}
		}
		for _, item := range ifaceStream {
			iface := item.(map[string]interface{})
			ip, _ := iface["ip_addr"].(string)
			if ip != "" && !strings.HasPrefix(ip, "192.168.") && !strings.HasPrefix(ip, "10.") && !strings.HasPrefix(ip, "172.") {
				return iface
			}
		}
	}
	return nil
}

func (c *IkuaiClient) GetRealDiskUsage() (int64, int64) {
	res := c.CallAPI("disk_mgmt", "show", map[string]interface{}{"TYPE": "data"})
	if res == nil {
		return 0, 0
	}
	data, ok := res["Data"].(map[string]interface{})
	if !ok {
		return 0, 0
	}

	totalSize := int64(0)
	totalUsed := int64(0)

	if diskList, ok := data["data"].([]interface{}); ok {
		for _, d := range diskList {
			diskMap := d.(map[string]interface{})
			if s, ok := diskMap["size"].(float64); ok {
				totalSize += int64(s)
			}
			if partitions, ok := diskMap["partition"].([]interface{}); ok {
				for _, p := range partitions {
					partMap := p.(map[string]interface{})
					if mounted, ok := partMap["mounted"].(map[string]interface{}); ok {
						if len(mounted) > 0 {
							used := safeInt64(mounted["mt_used"])
							totalUsed += used
						}
					}
				}
			}
		}
	}
	return totalSize, totalUsed
}

// ==========================================
// Agent 逻辑实现
// ==========================================

type IkuaiAgent struct {
	Client                *IkuaiClient
	Running               bool
	WS                    *websocket.Conn
	LastBasicInfoReport   int64
	mu                    sync.Mutex
}

func NewIkuaiAgent() *IkuaiAgent {
	return &IkuaiAgent{
		Client: NewIkuaiClient(),
	}
}

func (a *IkuaiAgent) GenerateWSURL() string {
	u, err := url.Parse(KomariEndpoint)
	if err != nil {
		base := strings.Replace(KomariEndpoint, "https", "wss", 1)
		base = strings.Replace(base, "http", "ws", 1)
		return fmt.Sprintf("%s/api/clients/report?token=%s", base, KomariToken)
	}
	if u.Scheme == "https" {
		u.Scheme = "wss"
	} else {
		u.Scheme = "ws"
	}
	u.Path = "/api/clients/report"
	q := u.Query()
	q.Set("token", KomariToken)
	u.RawQuery = q.Encode()
	return u.String()
}

func (a *IkuaiAgent) GetPublicIpFromIkuai() string {
	res := a.Client.CallAPI("monitor_iface", "show", map[string]interface{}{"TYPE": "iface_check"})
	if res != nil {
		if data, ok := res["Data"].(map[string]interface{}); ok {
			if list, ok := data["iface_check"].([]interface{}); ok {
				for _, item := range list {
					iface := item.(map[string]interface{})
					if ip, ok := iface["ip_addr"].(string); ok && ip != "" {
						if !strings.HasPrefix(ip, "192.168.") && !strings.HasPrefix(ip, "10.") {
							return ip
						}
					}
				}
			}
		}
	}
	return ""
}

func (a *IkuaiAgent) GetTotalMemory(sysStat map[string]interface{}) int64 {
	if memMap, ok := sysStat["memory"].(map[string]interface{}); ok {
		if val, ok := memMap["total"]; ok {
			return safeInt64(val) * 1024
		}
	}
	hwRes := a.Client.CallAPI("hardwareinfo", "show", nil)
	if hwRes != nil {
		hwInfo := getMap(hwRes, "Data", "hardwareinfo")
		if val, ok := hwInfo["memory"]; ok {
			return safeInt64(val) * 1024 * 1024
		}
	}
	return 0
}

func (a *IkuaiAgent) FormatBasicInfo() BasicInfoPayload {
	hwRes := a.Client.CallAPI("hardwareinfo", "show", nil)
	hwInfo := map[string]interface{}{}
	if hwRes != nil {
		hwInfo = getMap(hwRes, "Data", "hardwareinfo")
	}

	sysStats := a.Client.GetSystemStats()
	verStr := ""
	if sysStats != nil {
		if v, ok := getMap(sysStats, "verinfo")["verstring"].(string); ok {
			verStr = v
		}
	}

	arch := runtime.GOARCH
	if arch == "amd64" {
		arch = "x86_64"
	}

	ipv4 := a.GetPublicIpFromIkuai()
	if ipv4 == "" {
		ipv4 = "127.0.0.1"
	}
	cpuName, _ := hwInfo["cpumodel"].(string)
	if cpuName == "" {
		cpuName = "Unknown"
	}

	cpuCores := uint64(0)
	if val, ok := hwInfo["cpucores"]; ok {
		cpuCores = uint64(safeInt64(val))
	}
	if cpuCores == 0 {
		cpuCores = 1
	}

	memTotal := uint64(0)
	if sysStats != nil {
		memTotal = uint64(a.GetTotalMemory(sysStats))
	}

	var diskTotal uint64
	hddInfo, _ := hwInfo["hdd"].(string)
	if strings.Contains(hddInfo, "GB") {
		re := regexp.MustCompile(`\((\d+\.?\d*)GB\)`)
		matches := re.FindStringSubmatch(hddInfo)
		if len(matches) > 1 {
			gb, _ := strconv.ParseFloat(matches[1], 64)
			diskTotal = uint64(gb * 1024 * 1024 * 1024)
		}
	}

	osInfo := "iKuai"
	if verStr != "" {
		osInfo = fmt.Sprintf("iKuai (%s)", verStr)
	}

	return BasicInfoPayload{
		Arch:           arch,
		CpuCores:       cpuCores,
		CpuName:        cpuName,
		DiskTotal:      diskTotal,
		GpuName:        "None",
		Ipv4:           ipv4,
		Ipv6:           "",
		MemTotal:       memTotal,
		Os:             osInfo,
		KernelVersion:  "Linux",
		SwapTotal:      0,
		Version:        "1.1.40",
		Virtualization: "None",
	}
}

func (a *IkuaiAgent) FormatMonitoringData() MonitorPayload {
	sysStat := a.Client.GetSystemStats()
	if sysStat == nil {
		sysStat = map[string]interface{}{}
	}
	hpStat := a.Client.GetHomepageStats()

	// 1. CPU
	var cpuUsage float64
	if cpus, ok := sysStat["cpu"].([]interface{}); ok && len(cpus) > 0 {
		total := 0.0
		count := 0
		for _, v := range cpus {
			total += safeFloat64(v)
			count++
		}
		if count > 0 {
			cpuUsage = total / float64(count)
		}
	} else {
		p, _ := cpu.Percent(0, false)
		if len(p) > 0 {
			cpuUsage = p[0]
		}
	}
	if math.IsNaN(cpuUsage) {
		cpuUsage = 0
	}

	// 2. 内存
	memTotal := a.GetTotalMemory(sysStat)
	if memTotal == 0 {
		memTotal = 3 * 1024 * 1024 * 1024
	}

	var memUsed int64
	if memMap, ok := sysStat["memory"].(map[string]interface{}); ok {
		if val, ok := memMap["used"]; ok {
			usedPct := safeFloat64(val)
			memUsed = int64(float64(memTotal) * usedPct / 100.0)
		}
	}
	if memUsed == 0 {
		memUsed = int64(float64(memTotal) * 0.2)
	}

	// 3. 网络
	var netUp, netDown, netTotalUp, netTotalDown int64
	wanStats := a.Client.GetWanNetworkStats()
	if wanStats != nil {
		netUp = safeInt64(wanStats["upload"])
		netDown = safeInt64(wanStats["download"])
		if val, ok := wanStats["total_up"]; ok {
			netTotalUp = safeInt64(val)
		} else {
			netTotalUp = netUp
		}
		if val, ok := wanStats["total_down"]; ok {
			netTotalDown = safeInt64(val)
		} else {
			netTotalDown = netDown
		}
	}
	netUpRate := netUp / 3
	netDownRate := netDown / 3

	// 4. 连接数
	var tcpConn int64
	if stream, ok := sysStat["stream"].(map[string]interface{}); ok {
		tcpConn = safeInt64(stream["connect_num"])
	}

	// 5. 负载
	var load1, load5, load15 float64
	if loadMap, ok := sysStat["load"].(map[string]interface{}); ok {
		load1 = safeFloat64(loadMap["load1"])
		load5 = safeFloat64(loadMap["load5"])
		load15 = safeFloat64(loadMap["load15"])
	}
	if load1 == 0 && load5 == 0 && load15 == 0 {
		loadVal := cpuUsage / 100.0
		load1 = math.Round(loadVal*100) / 100
		load5 = math.Round(loadVal*0.8*100) / 100
		load15 = math.Round(loadVal*0.6*100) / 100
	}

	// 6. Uptime
	var uptime int64
	if val, ok := sysStat["uptime"]; ok {
		uptime = safeInt64(val)
	}
	if uptime == 0 && hpStat != nil {
		if sys, ok := hpStat["sysstat"].(map[string]interface{}); ok {
			if val, ok := sys["uptime"]; ok {
				uptime = safeInt64(val)
			}
		}
	}
	if uptime == 0 {
		bt, _ := host.BootTime()
		uptime = int64(time.Now().Unix()) - int64(bt)
	}
	if uptime <= 0 { uptime = 1 }

	// 7. Process (修正：使用 int64 类型)
	var processCount int64 = 0
	rawTemp := sysStat["cputemp"]
	
	if temps, ok := rawTemp.([]interface{}); ok && len(temps) > 0 {
		processCount = int64(safeFloat64(temps[0]))
	} else {
		// 回退：使用 TCP 连接数
		processCount = tcpConn
	}
	if processCount == 0 { processCount = 1 }

	// 8. 磁盘
	diskTotalReal, diskUsedReal := a.Client.GetRealDiskUsage()
	if diskTotalReal == 0 {
		hwRes := a.Client.CallAPI("hardwareinfo", "show", nil)
		if hwRes != nil {
			hwInfo := getMap(hwRes, "Data", "hardwareinfo")
			hddInfo, _ := hwInfo["hdd"].(string)
			if strings.Contains(hddInfo, "GB") {
				re := regexp.MustCompile(`\((\d+\.?\d*)GB\)`)
				matches := re.FindStringSubmatch(hddInfo)
				if len(matches) > 1 {
					gb, _ := strconv.ParseFloat(matches[1], 64)
					diskTotalReal = int64(gb * 1024 * 1024 * 1024)
				}
			}
		}
	}
	if diskUsedReal == 0 && diskTotalReal > 0 {
		diskUsedReal = int64(float64(diskTotalReal) * 0.2)
	}

	msg := fmt.Sprintf("iKuai Monitor - CPU: %.1f%%, RAM: %.1fGB, Conn: %d", 
		cpuUsage, float64(memUsed)/1024/1024/1024, tcpConn)

	return MonitorPayload{
		Cpu:         CpuStats{Usage: math.Round(cpuUsage*100) / 100},
		Ram:         RamStats{Total: memTotal, Used: memUsed},
		Swap:        SwapStats{Total: 0, Used: 0},
		Load:        LoadStats{Load1: load1, Load5: load5, Load15: load15},
		Disk:        DiskStats{Total: diskTotalReal, Used: diskUsedReal},
		Network:     NetStats{
			Up: netUpRate, Down: netDownRate, 
			TotalUp: netTotalUp, TotalDown: netTotalDown,
		},
		Connections: ConnStats{Tcp: tcpConn, Udp: 0},
		Uptime:      uptime,
		Process:     processCount,
		Message:     msg,
	}
}

// ==========================================
// WS 连接管理 (并发安全 & 修复配置引用)
// ==========================================

func (a *IkuaiAgent) StartWebsocket() {
	urlStr := a.GenerateWSURL()
	dialer := websocket.Dialer{
		// 修复：这里使用全局变量 IgnoreUnsafeCert，而不是 a.IgnoreUnsafeCert
		TLSClientConfig: &tls.Config{InsecureSkipVerify: IgnoreUnsafeCert},
	}
	
	headers := http.Header{}
	headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) iKuaiAgent/Go")
	if u, err := url.Parse(KomariEndpoint); err == nil {
		origin := fmt.Sprintf("%s://%s", u.Scheme, u.Host)
		headers.Add("Origin", origin)
	}

	log.Printf("连接WS: %s", urlStr)
	conn, _, err := dialer.Dial(urlStr, headers)
	if err != nil {
		log.Printf("WS连接失败: %v, 5秒后重试", err)
		time.AfterFunc(5*time.Second, a.StartWebsocket)
		return
	}

	a.mu.Lock()
	a.WS = conn
	a.mu.Unlock()

	go func() {
		defer func() {
			a.mu.Lock()
			if a.WS != nil {
				a.WS.Close()
				a.WS = nil
			}
			a.mu.Unlock()
		}()

		for {
			a.mu.Lock()
			if a.WS == nil {
				a.mu.Unlock()
				break
			}
			conn := a.WS
			a.mu.Unlock()

			_, _, err := conn.ReadMessage()
			if err != nil {
				log.Printf("WS断开 (Read): %v", err)
				if a.Running {
					time.AfterFunc(5*time.Second, a.StartWebsocket)
				}
				break
			}
		}
	}()
}

func (a *IkuaiAgent) ReportBasicInfo() {
	info := a.FormatBasicInfo()
	urlStr := fmt.Sprintf("%s/api/clients/uploadBasicInfo?token=%s", KomariEndpoint, KomariToken)
	jsonData, _ := json.Marshal(info)

	client := &http.Client{
		Timeout: 30 * time.Second,
		Transport: &http.Transport{
			// 修复：这里使用全局变量 IgnoreUnsafeCert
			TLSClientConfig: &tls.Config{InsecureSkipVerify: IgnoreUnsafeCert},
		},
	}
	resp, err := client.Post(urlStr, "application/json", bytes.NewBuffer(jsonData))
	if err == nil {
		defer resp.Body.Close()
		log.Printf("基础信息上报: %s", resp.Status)
	} else {
		log.Printf("基础信息上报失败: %v", err)
	}
}

func (a *IkuaiAgent) Start() {
	if !a.Client.Login() {
		log.Println("ikuai登录失败")
		return
	}
	a.Running = true
	a.ReportBasicInfo()
	a.StartWebsocket()

	ticker := time.NewTicker(time.Duration(WebsocketInterval * 1000) * time.Millisecond)
	for a.Running {
		select {
		case <-ticker.C:
			payload := a.FormatMonitoringData()
			if flag.Lookup("test").Value.String() == "true" {
				b, _ := json.Marshal(payload)
				log.Printf("DEBUG: %s", string(b))
			}

			a.mu.Lock()
			if a.WS != nil {
				a.WS.SetWriteDeadline(time.Now().Add(10 * time.Second))
				err := a.WS.WriteJSON(payload)
				if err != nil {
					log.Printf("发送失败: %v", err)
					a.WS.Close()
					a.WS = nil
				}
			}
			a.mu.Unlock()

			// 检查是否需要上报基础信息
			if time.Now().Unix()-a.LastBasicInfoReport > int64(BasicInfoInterval*60) {
				a.ReportBasicInfo()
				a.LastBasicInfoReport = time.Now().Unix()
			}
		}
	}
}

func main() {
	// 定义命令行参数
	flag.StringVar(&IkuaiBaseURL, "ikuai-url", "https://192.168.123.1", "iKuai路由器地址")
	flag.StringVar(&IkuaiUser, "ikuai-user", "admin", "iKuai用户名")
	flag.StringVar(&IkuaiPwd, "ikuai-pwd", "admin", "iKuai密码")
	flag.DurationVar(&IkuaiTimeout, "timeout", 10*time.Second, "API超时时间")
	
	flag.StringVar(&KomariEndpoint, "server", "https://192.168.123.254", "Komari服务器地址")
	flag.StringVar(&KomariToken, "token", "666666", "Komari Token")
	flag.Float64Var(&WebsocketInterval, "interval", 5.0, "WS上报间隔(秒)")
	flag.IntVar(&BasicInfoInterval, "info-interval", 1, "基础信息上报间隔(分钟)")
	flag.BoolVar(&IgnoreUnsafeCert, "insecure", false, "忽略SSL证书验证")
	
	testMode := flag.Bool("test", false, "测试模式")
	
	flag.Parse()

	if *testMode {
		fmt.Println("=== 测试模式启动 ===")
	}

	agent := NewIkuaiAgent()
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		agent.Running = false
		agent.mu.Lock()
		if agent.WS != nil {
			agent.WS.Close()
		}
		agent.mu.Unlock()
		os.Exit(0)
	}()
	agent.Start()
}