package handler

import (
	"net"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"time"

	"git.zkcoi.com/zkcoi/meshray/internal/model"
	sqlite "git.zkcoi.com/zkcoi/meshray/internal/store/sqlite"
	"github.com/gin-gonic/gin"
	"github.com/shirou/gopsutil/v4/cpu"
	"github.com/shirou/gopsutil/v4/disk"
	"github.com/shirou/gopsutil/v4/host"
	"github.com/shirou/gopsutil/v4/mem"
	gopsutilNet "github.com/shirou/gopsutil/v4/net"
	"go.uber.org/zap"
)

// DashboardHandler Dashboard Handler
type DashboardHandler struct {
	logger *zap.Logger
	store  *sqlite.Store
}

// NewDashboardHandler 创建 Dashboard Handler
func NewDashboardHandler(store *sqlite.Store, logger *zap.Logger) *DashboardHandler {
	return &DashboardHandler{
		logger: logger,
		store:  store,
	}
}

// GetStats 获取统计数据
func (h *DashboardHandler) GetStats(c *gin.Context) {
	var deviceCount, networkCount, onlineCount int64

	// 统计设备数量
	h.store.DB().Model(&model.Device{}).Count(&deviceCount)

	// 统计网络数量
	h.store.DB().Model(&model.Network{}).Count(&networkCount)

	// 统计在线设备数量
	h.store.DB().Model(&model.Device{}).Where("status = ?", "online").Count(&onlineCount)

	c.JSON(http.StatusOK, gin.H{
		"data": gin.H{
			"total_devices":  deviceCount,
			"total_networks": networkCount,
			"online_devices": onlineCount,
		},
	})
}

// GetRecentLogs 获取最近日志
func (h *DashboardHandler) GetRecentLogs(c *gin.Context) {
	limitStr := c.DefaultQuery("limit", "10")
	limit := 10
	if l, err := strconv.Atoi(limitStr); err == nil && l > 0 {
		limit = l
	}

	// 从数据库查询最近的 AuditLog
	var logs []model.AuditLog
	if err := h.store.DB().
		Order("created_at DESC").
		Limit(limit).
		Find(&logs).Error; err != nil {
		h.logger.Error("查询日志失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "查询日志失败",
		})
		return
	}

	// 转换为前端格式
	type LogEntry struct {
		ID         uint64 `json:"id"`
		Timestamp  string `json:"timestamp"`
		Message    string `json:"message"`
		Action     string `json:"action"`
		OperatorIP string `json:"operator_ip"`
		Type       string `json:"type"` // info, success, warning, error
	}

	logEntries := make([]LogEntry, 0, len(logs))
	for _, log := range logs {
		// 从 Detail 中提取信息构建 Message
		message := log.Action
		if log.Detail != "" {
			message = log.Detail
		}

		logEntries = append(logEntries, LogEntry{
			ID:         uint64(log.ID),
			Timestamp:  log.CreatedAt.Format(time.RFC3339),
			Message:    message,
			Action:     log.Action,
			OperatorIP: log.OperatorIP,
			Type:       "info", // AuditLog 默认类型
		})
	}

	c.JSON(http.StatusOK, gin.H{
		"data": logEntries,
	})
}

// GetSystemInfo 获取系统信息
func (h *DashboardHandler) GetSystemInfo(c *gin.Context) {
	// 获取主机信息
	hostInfo, err := host.Info()
	if err != nil {
		h.logger.Warn("获取主机信息失败", zap.Error(err))
		hostInfo = &host.InfoStat{} // 使用空对象避免 nil 指针
	}

	// 获取 CPU 信息
	cpuPercent, _ := cpu.Percent(0, false)
	cpuUsage := float64(0)
	if len(cpuPercent) > 0 {
		cpuUsage = cpuPercent[0]
	}

	// 获取内存信息
	memInfo, _ := mem.VirtualMemory()

	// 获取磁盘信息
	diskInfo, _ := disk.Usage("/")
	// Windows 下使用 C:\
	if runtime.GOOS == "windows" {
		diskInfo, _ = disk.Usage("C:/")
	}

	// 获取网络 IO
	netIO, _ := gopsutilNet.IOCounters(false)

	// 获取本机 IP（IPv4 + IPv6）
	ipv4, ipv6 := getLocalIPs()
	ip := ipv4 // 默认返回 IPv4
	if ipv4 == "unknown" && ipv6 != "unknown" {
		ip = ipv6 // 如果只有 IPv6，则返回 IPv6
	}

	// 计算运行时长（小时）
	uptimeHours := float64(hostInfo.Uptime) / 3600.0

	c.JSON(http.StatusOK, gin.H{
		"data": gin.H{
			// 基础信息
			"hostname":   hostInfo.Hostname,
			"os":         hostInfo.OS,
			"platform":   hostInfo.Platform,
			"os_version": hostInfo.PlatformVersion,
			"kernel":     hostInfo.KernelVersion,
			"arch":       runtime.GOARCH,

			// CPU
			"cpu_count": runtime.NumCPU(),
			"cpu_usage": cpuUsage,
			"cpu_model": getCPUModel(), // 从 cpu.Info() 获取

			// 内存
			"memory_total":   int(memInfo.Total / 1024 / 1024), // MB
			"memory_used":    int(memInfo.Used / 1024 / 1024),  // MB
			"memory_percent": memInfo.UsedPercent,
			"memory_alloc":   int(runtime.MemStats{}.Alloc / 1024 / 1024), // Go 内存

			// 磁盘
			"disk_total":   int(diskInfo.Total / 1024 / 1024 / 1024), // GB
			"disk_used":    int(diskInfo.Used / 1024 / 1024 / 1024),  // GB
			"disk_percent": diskInfo.UsedPercent,

			// 网络
			"net_sent": netIO[0].BytesSent,
			"net_recv": netIO[0].BytesRecv,

			// 运行时长
			"boot_time": formatBootTime(hostInfo),
			"uptime":    uptimeHours,

			// IP 地址（同时返回 IPv4 和 IPv6）
			"ip":   ip,   // 保持向后兼容
			"ipv4": ipv4, // IPv4 地址
			"ipv6": ipv6, // IPv6 地址
		},
	})
}

// getLocalIPs 获取本机 IPv4 和 IPv6 地址
func getLocalIPs() (ipv4, ipv6 string) {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return "unknown", "unknown"
	}

	for _, addr := range addrs {
		if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
			// 检查是否为公网地址（可选，目前保留私有地址）
			if ipNet.IP.To4() != nil {
				// 优先选择非链路本地地址
				if ipv4 == "" || !ipNet.IP.IsLinkLocalUnicast() {
					ipv4 = ipNet.IP.String()
				}
			} else if ipNet.IP.To16() != nil {
				// IPv6
				if ipv6 == "" || !ipNet.IP.IsLinkLocalUnicast() {
					ipv6 = ipNet.IP.String()
				}
			}
		}
	}

	if ipv4 == "" {
		ipv4 = "unknown"
	}
	if ipv6 == "" {
		ipv6 = "unknown"
	}
	return ipv4, ipv6
}

// formatBootTime 格式化启动时间
func formatBootTime(hostInfo *host.InfoStat) string {
	if hostInfo == nil || hostInfo.BootTime == 0 {
		return "unknown"
	}
	return time.Unix(int64(hostInfo.BootTime), 0).Format("2006-01-02 15:04:05")
}

// GetLinkDistribution 获取链路分布
func (h *DashboardHandler) GetLinkDistribution(c *gin.Context) {
	// 查询所有网络
	var networks []model.Network
	if err := h.store.DB().Find(&networks).Error; err != nil {
		h.logger.Error("查询网络失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "查询网络失败",
		})
		return
	}

	// 构建链路分布数据
	distribution := make([]gin.H, 0, len(networks))
	totalP2P := 0
	totalRelay := 0

	for _, network := range networks {
		// 查询该网络下的所有设备
		var devices []model.Device
		if err := h.store.DB().Where("network_id = ?", network.ID).Find(&devices).Error; err != nil {
			h.logger.Warn("查询设备失败", zap.Uint64("network_id", network.ID), zap.Error(err))
			continue
		}

		// 统计 P2P 和 Relay 连接
		p2pCount := 0
		relayCount := 0

		for _, device := range devices {
			// 根据 Endpoint 判断是 P2P 还是 Relay
			// 如果 Endpoint 为空或为内网地址，认为是 P2P
			// 如果 Endpoint 包含中继端口（如 53493），认为是 Relay
			if device.Endpoint == "" {
				p2pCount++
			} else if isRelayEndpoint(device.Endpoint) {
				relayCount++
			} else {
				p2pCount++
			}
		}

		totalP2P += p2pCount
		totalRelay += relayCount

		distribution = append(distribution, gin.H{
			"network_id":   network.ID,
			"network_name": network.Name,
			"p2p_count":    p2pCount,
			"relay_count":  relayCount,
			"total_peers":  len(devices),
			"mode":         network.Mode, // native / userspace
		})
	}

	// 返回总体统计和详细分布
	c.JSON(http.StatusOK, gin.H{
		"data": gin.H{
			"summary": gin.H{
				"total_p2p":   totalP2P,
				"total_relay": totalRelay,
				"total":       totalP2P + totalRelay,
				"p2p_percent": calculatePercent(totalP2P, totalP2P+totalRelay),
			},
			"by_network": distribution,
		},
	})
}

// isRelayEndpoint 判断是否为中继端点
func isRelayEndpoint(endpoint string) bool {
	// 简单的启发式判断：如果端口在常见 TURN 端口范围内
	_, port, err := net.SplitHostPort(endpoint)
	if err != nil {
		return false
	}

	// 常见 TURN/Relay 端口
	relayPorts := []string{"53493", "53494", "53495", "3478", "5349"}
	for _, p := range relayPorts {
		if port == p {
			return true
		}
	}
	return false
}

// calculatePercent 计算百分比
func calculatePercent(part, total int) float64 {
	if total == 0 {
		return 0
	}
	return float64(part) / float64(total) * 100
}

// ClearLogs 清理日志文件
func (h *DashboardHandler) ClearLogs(c *gin.Context) {
	logPath := "./logs"

	// 检查日志目录是否存在
	if _, err := os.Stat(logPath); os.IsNotExist(err) {
		c.JSON(http.StatusOK, gin.H{
			"message": "日志目录不存在",
		})
		return
	}

	// 读取所有日志文件
	files, err := filepath.Glob(filepath.Join(logPath, "*.log"))
	if err != nil {
		h.logger.Error("读取日志文件失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "读取日志文件失败",
		})
		return
	}

	// 删除所有日志文件
	deletedCount := 0
	for _, file := range files {
		if err := os.Remove(file); err != nil {
			h.logger.Warn("删除日志文件失败", zap.String("file", file), zap.Error(err))
			continue
		}
		deletedCount++
	}

	h.logger.Info("清理日志完成", zap.Int("deleted", deletedCount))
	c.JSON(http.StatusOK, gin.H{
		"message": "日志清理完成",
		"deleted": deletedCount,
	})
}

// getCPUModel 获取 CPU 型号
func getCPUModel() string {
	cpuInfos, err := cpu.Info()
	if err != nil || len(cpuInfos) == 0 {
		return "Unknown"
	}
	return cpuInfos[0].ModelName
}
