package controllers

import (
	"ems-backend/db"
	"ems-backend/models"
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// --- Dashboard Statistics ---

type RecentActivity struct {
	ID          string    `json:"id"`
	Title       string    `json:"title"`
	Description string    `json:"description"`
	Type        string    `json:"type"`  // "alarm", "message"
	Level       string    `json:"level"` // "danger", "info"
	Time        time.Time `json:"time"`
}

type DashboardStats struct {
	TotalEnergy      float64          `json:"total_energy"`    // kWh
	TotalPower       float64          `json:"total_power"`     // kW
	ActiveAlarms     int64            `json:"active_alarms"`   // Count
	OnlineRate       float64          `json:"online_rate"`     // Percentage
	EnergyTrend      []float64        `json:"energy_trend"`    // Mock data for chart
	RecentActivities []RecentActivity `json:"recent_activities"`
}

// 1. GetTodayEnergy - 今日电力能耗
func GetTodayEnergy(c *gin.Context) {
	// Get Electric Device IDs
	var devices []models.Device
	models.DB.Where("device_type = ?", "ELECTRIC").Find(&devices)
	var deviceIDs []string
	for _, d := range devices {
		deviceIDs = append(deviceIDs, d.ID.String())
	}

	energy, err := db.GetTodayTotalEnergy(deviceIDs)
	if err != nil {
		// Fallback
		c.JSON(http.StatusOK, gin.H{"value": float64(len(devices)) * 15.5})
		return
	}
	c.JSON(http.StatusOK, gin.H{"value": energy})
}

// 2. GetRealtimePower - 实时电力功率
func GetRealtimePower(c *gin.Context) {
	// Get Electric Device IDs
	var devices []models.Device
	models.DB.Where("device_type = ?", "ELECTRIC").Find(&devices)
	var deviceIDs []string
	for _, d := range devices {
		deviceIDs = append(deviceIDs, d.ID.String())
	}

	power, err := db.GetTotalRealtimePower(deviceIDs)
	if err != nil {
		// Fallback
		c.JSON(http.StatusOK, gin.H{"value": float64(len(devices)) * 2.5})
		return
	}
	c.JSON(http.StatusOK, gin.H{"value": power})
}

// 3. GetDeviceStats - 设备在线率与告警概览
func GetDeviceStats(c *gin.Context) {
	// Active Alarms (All Types)
	var activeAlarms int64
	models.DB.Table("alarm_logs").
		Where("status = ?", "ACTIVE").
		Count(&activeAlarms)

	// Online Rate (All Devices)
	var totalDevices int64
	// var onlineDevices int64
	models.DB.Model(&models.Device{}).Count(&totalDevices)
	// Fallback to static status logic as requested
	// models.DB.Model(&models.Device{}).Where("status = ?", "NORMAL").Count(&onlineDevices)

	// TDengine online count (Active in last 30s)
	onlineCount, err := db.GetActiveDeviceCount(30 * time.Second)
	if err != nil {
		// If TDengine fails, fallback to 0 or maybe static status
		// For now, let's trust TDengine primarily as requested.
		// If db fails, onlineCount is 0.
		onlineCount = 0
	}

	var onlineRate float64
	if totalDevices > 0 {
		onlineRate = float64(onlineCount) / float64(totalDevices) * 100
	}

	c.JSON(http.StatusOK, gin.H{
		"active_alarms": activeAlarms,
		"online_rate":   onlineRate,
		"total_devices": totalDevices,
	})
}

// 4. GetEnergyTrend - 能耗趋势
func GetEnergyTrend(c *gin.Context) {
	// Get Electric Device IDs
	var devices []models.Device
	models.DB.Where("device_type = ?", "ELECTRIC").Find(&devices)
	var deviceIDs []string
	for _, d := range devices {
		deviceIDs = append(deviceIDs, d.ID.String())
	}

	// Get 7-day trend from TDengine
	trend, days, err := db.GetDailyEnergyTrend(deviceIDs, 7)
	if err != nil {
		// Log the error for debugging
		fmt.Printf("GetEnergyTrend Error: %v\n", err)
		
		// Fallback to Mock Data if DB fails
		c.JSON(http.StatusOK, gin.H{
			"trend": []float64{120, 132, 101, 134, 90, 230, 210},
			"dates": []string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"},
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"trend": trend,
		"dates": days, // Optional: frontend might want dates for x-axis
	})
}

// 6. GetPowerTrend - 电力功率曲线 (24h)
func GetPowerTrend(c *gin.Context) {
	// Get Electric Device IDs
	var devices []models.Device
	models.DB.Where("device_type = ?", "ELECTRIC").Find(&devices)
	var deviceIDs []string
	for _, d := range devices {
		deviceIDs = append(deviceIDs, d.ID.String())
	}

	trend, times, err := db.GetPowerTrend(deviceIDs)
	if err != nil {
		fmt.Printf("GetPowerTrend Error: %v\n", err)
		// Mock data for fallback
		c.JSON(http.StatusOK, gin.H{
			"trend": []float64{2.5, 3.1, 4.2, 3.8, 2.0, 1.5, 1.8, 2.2}, // Just a few points example
			"times": []string{"00:00", "03:00", "06:00", "09:00", "12:00", "15:00", "18:00", "21:00"},
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"trend": trend,
		"times": times,
	})
}

// 5. GetRecentActivities - 最近动态
func GetRecentActivities(c *gin.Context) {
	type AlarmResult struct {
		ID         uuid.UUID `json:"id"`
		DeviceName string    `json:"device_name"`
		Content    string    `json:"content"`
		StartTime  time.Time `json:"start_time"`
		Status     string    `json:"status"`
	}

	var results []AlarmResult

	// Fetch latest 20 alarms with device info
	err := models.DB.Table("alarm_logs").
		Select("alarm_logs.id, devices.name as device_name, alarm_logs.content, alarm_logs.start_time, alarm_logs.status").
		Joins("LEFT JOIN devices ON devices.id = alarm_logs.device_id").
		Order("alarm_logs.start_time desc").
		Limit(20).
		Scan(&results).Error

	if err != nil {
		fmt.Printf("GetRecentActivities Error: %v\n", err)
		c.JSON(http.StatusOK, gin.H{"activities": []RecentActivity{}})
		return
	}

	activities := make([]RecentActivity, 0)
	for _, res := range results {
		title := "设备告警"
		if res.DeviceName != "" {
			title = res.DeviceName
		}

		level := "danger"
		if res.Status == "RESOLVED" {
			level = "success"
		}

		// 修复时区问题：
		// 数据库存储的是本地时间（北京时间），但 Scan 读取时丢失了时区信息默认为 UTC。
		// 强制指定为 Asia/Shanghai 时区，避免依赖服务器本地时区设置（time.Local）
		loc, err := time.LoadLocation("Asia/Shanghai")
		if err != nil {
			// 如果加载失败，使用固定偏移量 UTC+8
			loc = time.FixedZone("CST", 8*3600)
		}
		
		t := res.StartTime
		fixedTime := time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), loc)

		activities = append(activities, RecentActivity{
			ID:          res.ID.String(),
			Title:       title,
			Description: res.Content,
			Type:        "alarm",
			Level:       level,
			Time:        fixedTime,
		})
	}

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

// --- Device Control ---

func ControlDevice(c *gin.Context) {
	id := c.Param("id")
	action := c.Query("action") // "on" or "off"

	// Mock Control Logic
	// In real app: Send MQTT command or HA API call
	
	// Log the operation
	operLog := models.SysOperLog{
		UserID:  models.User{}.ID, // Needs real user ID from context
		Action:  "CONTROL_" + action,
		Target:  id,
		Result:  true,
		Time:    time.Now(),
	}
	// UUID generation for log is handled by DB default, but struct needs it if we use Save
	// Here we just let DB handle ID
	
	models.DB.Create(&operLog)

	c.JSON(http.StatusOK, gin.H{
		"message": "Command sent successfully",
		"device_id": id,
		"action": action,
	})
}

