package main

import (
	"encoding/json"
	"fmt"
	"git.yeij.top/AskaEth/Cyrene/pkg/logger"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
)

// DeviceType 设备类型
type DeviceType string

const (
	TypeLight   DeviceType = "light"
	TypeAC      DeviceType = "ac"
	TypeCurtain DeviceType = "curtain"
	TypeSensor  DeviceType = "sensor"
	TypeLock    DeviceType = "lock"
)

// Device 设备状态
type Device struct {
	ID          string      `json:"id"`
	Name        string      `json:"name"`
	Type        DeviceType  `json:"type"`
	Status      string      `json:"status"`       // on/off/closed/open/locked/unlocked
	Brightness  int         `json:"brightness,omitempty"`
	Color       string      `json:"color,omitempty"`
	Temperature float64     `json:"temperature,omitempty"`
	Mode        string      `json:"mode,omitempty"`      // cool/heat/auto
	Position    int         `json:"position,omitempty"`  // curtain position 0-100
	Value       float64     `json:"value,omitempty"`     // sensor value
	Unit        string      `json:"unit,omitempty"`      // sensor unit
	Battery     int         `json:"battery,omitempty"`   // lock battery
	LastUpdated string      `json:"last_updated"`
	History     []HistoryEntry `json:"history,omitempty"`
}

// HistoryEntry 设备状态历史
type HistoryEntry struct {
	Timestamp string `json:"timestamp"`
	Field     string `json:"field"`
	OldValue  string `json:"old_value"`
	NewValue  string `json:"new_value"`
}

// DeviceStore 设备存储（线程安全）
type DeviceStore struct {
	mu       sync.RWMutex
	devices  map[string]*Device
	history  map[string][]HistoryEntry
}

func NewDeviceStore() *DeviceStore {
	ds := &DeviceStore{
		devices: make(map[string]*Device),
		history: make(map[string][]HistoryEntry),
	}
	ds.initDevices()
	return ds
}

func (ds *DeviceStore) initDevices() {
	now := time.Now().UTC().Format(time.RFC3339)

	devices := []*Device{
		{ID: "light-livingroom", Name: "客厅灯", Type: TypeLight, Status: "on", Brightness: 80, Color: "warm_white", LastUpdated: now},
		{ID: "light-bedroom", Name: "卧室灯", Type: TypeLight, Status: "off", Brightness: 0, Color: "warm_white", LastUpdated: now},
		{ID: "ac-livingroom", Name: "客厅空调", Type: TypeAC, Status: "on", Temperature: 26, Mode: "cool", LastUpdated: now},
		{ID: "ac-bedroom", Name: "卧室空调", Type: TypeAC, Status: "off", Temperature: 24, Mode: "auto", LastUpdated: now},
		{ID: "curtain-livingroom", Name: "客厅窗帘", Type: TypeCurtain, Status: "closed", Position: 0, LastUpdated: now},
		{ID: "sensor-temperature", Name: "温度传感器", Type: TypeSensor, Value: 25.5, Unit: "celsius", LastUpdated: now},
		{ID: "sensor-humidity", Name: "湿度传感器", Type: TypeSensor, Value: 60, Unit: "percent", LastUpdated: now},
		{ID: "lock-door", Name: "智能门锁", Type: TypeLock, Status: "locked", Battery: 85, LastUpdated: now},
	}

	for _, d := range devices {
		ds.devices[d.ID] = d
		ds.history[d.ID] = make([]HistoryEntry, 0)
	}
}

// GetAll 获取所有设备
func (ds *DeviceStore) GetAll() []*Device {
	ds.mu.RLock()
	defer ds.mu.RUnlock()

	result := make([]*Device, 0, len(ds.devices))
	for _, d := range ds.devices {
		cp := *d
		cp.History = nil // 列表不返回历史
		result = append(result, &cp)
	}
	return result
}

// Get 获取单个设备
func (ds *DeviceStore) Get(id string) *Device {
	ds.mu.RLock()
	defer ds.mu.RUnlock()

	d, ok := ds.devices[id]
	if !ok {
		return nil
	}
	cp := *d
	// 包含最近10条历史（RLock 可重入）
	if h, ok := ds.history[id]; ok && len(h) > 0 {
		start := 0
		if len(h) > 10 {
			start = len(h) - 10
		}
		cp.History = make([]HistoryEntry, len(h)-start)
		copy(cp.History, h[start:])
	} else {
		cp.History = []HistoryEntry{}
	}
	return &cp
}

// GetHistory 获取设备状态历史（最近10条）
func (ds *DeviceStore) GetHistory(id string) []HistoryEntry {
	ds.mu.RLock()
	defer ds.mu.RUnlock()

	h, ok := ds.history[id]
	if !ok || len(h) == 0 {
		return []HistoryEntry{}
	}

	start := 0
	if len(h) > 10 {
		start = len(h) - 10
	}
	result := make([]HistoryEntry, len(h[start:]))
	copy(result, h[start:])
	return result
}

// addHistory 添加历史记录
func (ds *DeviceStore) addHistory(id, field, oldVal, newVal string) {
	entry := HistoryEntry{
		Timestamp: time.Now().UTC().Format(time.RFC3339),
		Field:     field,
		OldValue:  oldVal,
		NewValue:  newVal,
	}
	ds.history[id] = append(ds.history[id], entry)
}

// Toggle 切换设备开关状态
func (ds *DeviceStore) Toggle(id string) (*Device, error) {
	ds.mu.Lock()
	defer ds.mu.Unlock()

	d, ok := ds.devices[id]
	if !ok {
		return nil, fmt.Errorf("设备 %s 不存在", id)
	}

	switch d.Type {
	case TypeLight:
		oldStatus := d.Status
		if d.Status == "on" {
			d.Status = "off"
			d.Brightness = 0
		} else {
			d.Status = "on"
			d.Brightness = 80
		}
		d.LastUpdated = time.Now().UTC().Format(time.RFC3339)
		ds.addHistory(id, "status", oldStatus, d.Status)

	case TypeAC:
		oldStatus := d.Status
		if d.Status == "on" {
			d.Status = "off"
		} else {
			d.Status = "on"
		}
		d.LastUpdated = time.Now().UTC().Format(time.RFC3339)
		ds.addHistory(id, "status", oldStatus, d.Status)

	case TypeCurtain:
		oldStatus := d.Status
		if d.Status == "closed" {
			d.Status = "open"
			d.Position = 100
		} else {
			d.Status = "closed"
			d.Position = 0
		}
		d.LastUpdated = time.Now().UTC().Format(time.RFC3339)
		ds.addHistory(id, "status", oldStatus, d.Status)

	case TypeLock:
		oldStatus := d.Status
		if d.Status == "locked" {
			d.Status = "unlocked"
		} else {
			d.Status = "locked"
		}
		d.LastUpdated = time.Now().UTC().Format(time.RFC3339)
		ds.addHistory(id, "status", oldStatus, d.Status)

	default:
		return nil, fmt.Errorf("设备类型 %s 不支持切换", d.Type)
	}

	cp := *d
	// 不能调用 ds.GetHistory(id)，因为当前已持有写锁，Go 的 RWMutex 不允许写锁重入读锁
	if h, ok := ds.history[id]; ok && len(h) > 0 {
		start := 0
		if len(h) > 10 {
			start = len(h) - 10
		}
		cp.History = make([]HistoryEntry, len(h)-start)
		copy(cp.History, h[start:])
	} else {
		cp.History = []HistoryEntry{}
	}
	return &cp, nil
}

// SetProperty 设置设备属性（状态、温度、亮度、位置、模式、颜色等）
func (ds *DeviceStore) SetProperty(id, field string, value interface{}) (*Device, error) {
	ds.mu.Lock()
	defer ds.mu.Unlock()

	d, ok := ds.devices[id]
	if !ok {
		return nil, fmt.Errorf("设备 %s 不存在", id)
	}

	now := time.Now().UTC().Format(time.RFC3339)

	switch field {
	case "status", "power":
		// 声明式电源控制：支持 "on"/"off"/"open"/"closed"/"locked"/"unlocked"
		// 同时支持中文值: "开"/"关"/"打开"/"关闭"
		// 支持布尔值: true/false → on/off
		var newStatus string
		switch v := value.(type) {
		case string:
			newStatus = normalizeStatus(v, d.Type)
			if newStatus == "" {
				return nil, fmt.Errorf("无效的状态值: %s (设备类型 %s 不支持此状态)", v, d.Type)
			}
		case bool:
			if v {
				newStatus = "on"
			} else {
				newStatus = "off"
			}
		case float64:
			if v == 0 {
				newStatus = "off"
			} else {
				newStatus = "on"
			}
		default:
			return nil, fmt.Errorf("status 需要字符串、布尔值或数字")
		}
		// 对于非 on/off 设备类型（curtain/lock），转换为对应状态
		switch d.Type {
		case TypeCurtain:
			if newStatus == "on" {
				newStatus = "open"
			} else if newStatus == "off" {
				newStatus = "closed"
			}
		case TypeLock:
			if newStatus == "on" {
				newStatus = "unlocked"
			} else if newStatus == "off" {
				newStatus = "locked"
			}
		}

		if d.Status == newStatus {
			// 状态未变化，直接返回
			cp := *d
			return &cp, nil
		}
		oldStatus := d.Status
		d.Status = newStatus
		// 根据设备类型设置关联属性
		switch d.Type {
		case TypeLight:
			if newStatus == "off" {
				d.Brightness = 0
			} else if d.Brightness == 0 {
				d.Brightness = 80
			}
		case TypeCurtain:
			if newStatus == "closed" {
				d.Position = 0
			} else {
				d.Position = 100
			}
		}
		d.LastUpdated = now
		ds.addHistory(id, "status", oldStatus, newStatus)

	case "temperature":
		v, ok := toFloat64(value)
		if !ok {
			return nil, fmt.Errorf("temperature 需要数字值")
		}
		if d.Type != TypeAC {
			return nil, fmt.Errorf("设备 %s (类型 %s) 不支持温度调节", d.Name, d.Type)
		}
		oldVal := fmt.Sprintf("%.1f", d.Temperature)
		d.Temperature = v
		d.LastUpdated = now
		ds.addHistory(id, "temperature", oldVal, fmt.Sprintf("%.1f", v))

	case "brightness":
		v, ok := toFloat64(value)
		if !ok {
			return nil, fmt.Errorf("brightness 需要数字值")
		}
		if d.Type != TypeLight {
			return nil, fmt.Errorf("设备 %s (类型 %s) 不支持亮度调节", d.Name, d.Type)
		}
		oldVal := fmt.Sprintf("%d", d.Brightness)
		d.Brightness = clampInt(int(v), 0, 100)
		d.LastUpdated = now
		ds.addHistory(id, "brightness", oldVal, fmt.Sprintf("%d", d.Brightness))

	case "position":
		v, ok := toFloat64(value)
		if !ok {
			return nil, fmt.Errorf("position 需要数字值")
		}
		if d.Type != TypeCurtain {
			return nil, fmt.Errorf("设备 %s (类型 %s) 不支持位置调节", d.Name, d.Type)
		}
		oldVal := fmt.Sprintf("%d", d.Position)
		d.Position = clampInt(int(v), 0, 100)
		d.LastUpdated = now
		ds.addHistory(id, "position", oldVal, fmt.Sprintf("%d", d.Position))

	case "mode":
		v, ok := value.(string)
		if !ok {
			return nil, fmt.Errorf("mode 需要字符串值")
		}
		if d.Type != TypeAC {
			return nil, fmt.Errorf("设备 %s (类型 %s) 不支持模式切换", d.Name, d.Type)
		}
		oldVal := d.Mode
		d.Mode = v
		d.LastUpdated = now
		ds.addHistory(id, "mode", oldVal, v)

	case "color":
		v, ok := value.(string)
		if !ok {
			return nil, fmt.Errorf("color 需要字符串值")
		}
		if d.Type != TypeLight {
			return nil, fmt.Errorf("设备 %s (类型 %s) 不支持颜色调节", d.Name, d.Type)
		}
		oldVal := d.Color
		d.Color = v
		d.LastUpdated = now
		ds.addHistory(id, "color", oldVal, v)

	default:
		return nil, fmt.Errorf("不支持的属性: %s", field)
	}

	cp := *d
	if h, ok := ds.history[id]; ok && len(h) > 0 {
		start := 0
		if len(h) > 10 {
			start = len(h) - 10
		}
		cp.History = make([]HistoryEntry, len(h)-start)
		copy(cp.History, h[start:])
	} else {
		cp.History = []HistoryEntry{}
	}
	return &cp, nil
}

// normalizeStatus 标准化电源状态值
// 支持英文: "on"/"off"/"open"/"closed"/"locked"/"unlocked"
// 支持中文: "开"/"关"/"打开"/"关闭"/"开启"/"解锁"/"锁定"/"上锁"
// 支持布尔兼容: "true"/"false"
// 返回空字符串表示无效值
func normalizeStatus(v string, dType DeviceType) string {
	switch strings.ToLower(strings.TrimSpace(v)) {
	case "on", "true", "开", "打开", "开启":
		return "on"
	case "off", "false", "关", "关闭":
		return "off"
	case "open":
		if dType == TypeCurtain {
			return "open"
		}
		return "on"
	case "closed":
		if dType == TypeCurtain {
			return "closed"
		}
		return "off"
	case "locked", "锁定", "上锁":
		return "locked"
	case "unlocked", "解锁":
		return "unlocked"
	default:
		return ""
	}
}

// toFloat64 将 interface{} 转换为 float64
func toFloat64(v interface{}) (float64, bool) {
	switch val := v.(type) {
	case float64:
		return val, true
	case float32:
		return float64(val), true
	case int:
		return float64(val), true
	case int64:
		return float64(val), true
	case json.Number:
		f, err := val.Float64()
		return f, err == nil
	default:
		return 0, false
	}
}

// clampInt 限制整数在 [min, max] 范围内
func clampInt(v, min, max int) int {
	if v < min {
		return min
	}
	if v > max {
		return max
	}
	return v
}

// SimulateFluctuation 模拟传感器随机波动
func (ds *DeviceStore) SimulateFluctuation() {
	ds.mu.Lock()
	defer ds.mu.Unlock()

	now := time.Now().UTC().Format(time.RFC3339)

	// 温度传感器: ±0.2°C
	if t, ok := ds.devices["sensor-temperature"]; ok {
		oldVal := t.Value
		t.Value += (rand.Float64()*0.4 - 0.2)
		t.Value = float64(int(t.Value*10)) / 10 // 保留一位小数
		t.LastUpdated = now
		ds.addHistory("sensor-temperature", "value", fmt.Sprintf("%.1f", oldVal), fmt.Sprintf("%.1f", t.Value))
	}

	// 湿度传感器: ±1%
	if h, ok := ds.devices["sensor-humidity"]; ok {
		oldVal := h.Value
		h.Value += float64(rand.Intn(3) - 1) // -1, 0, +1
		if h.Value < 0 {
			h.Value = 0
		}
		if h.Value > 100 {
			h.Value = 100
		}
		h.LastUpdated = now
		ds.addHistory("sensor-humidity", "value", fmt.Sprintf("%.0f", oldVal), fmt.Sprintf("%.0f", h.Value))
	}
}

func main() {
	logger.SetDefault(logger.New("iot-debug"))
	port := getEnv("IOT_DEBUG_PORT", "8083")
	store := NewDeviceStore()

	// 启动传感器波动模拟（每30秒）
	go func() {
		ticker := time.NewTicker(30 * time.Second)
		defer ticker.Stop()
		for range ticker.C {
			store.SimulateFluctuation()
		}
	}()

	mux := http.NewServeMux()

	// GET /api/v1/devices - 列出所有设备
	mux.HandleFunc("/api/v1/devices", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}
		devices := store.GetAll()
		writeJSON(w, http.StatusOK, map[string]interface{}{
			"devices": devices,
			"total":   len(devices),
		})
	})

	// GET /api/v1/devices/{id} - 获取单个设备
	// POST /api/v1/devices/{id}/toggle - 切换设备
	mux.HandleFunc("/api/v1/devices/", func(w http.ResponseWriter, r *http.Request) {
		path := strings.TrimPrefix(r.URL.Path, "/api/v1/devices/")
		parts := strings.Split(path, "/")

		if len(parts) == 0 || parts[0] == "" {
			http.Error(w, "缺少设备ID", http.StatusBadRequest)
			return
		}

		deviceID := parts[0]

		// POST /api/v1/devices/{id}/toggle
		if len(parts) == 2 && parts[1] == "toggle" {
			if r.Method != http.MethodPost {
				http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
				return
			}
			device, err := store.Toggle(deviceID)
			if err != nil {
				writeJSON(w, http.StatusNotFound, map[string]string{"error": err.Error()})
				return
			}
			writeJSON(w, http.StatusOK, map[string]interface{}{
				"device": device,
				"action": "toggled",
			})
			return
		}

		// POST /api/v1/devices/{id}/set - 设置设备属性
		if len(parts) == 2 && parts[1] == "set" {
			if r.Method != http.MethodPost {
				http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
				return
			}
			var req struct {
				Field string      `json:"field"`
				Value interface{} `json:"value"`
			}
			if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
				writeJSON(w, http.StatusBadRequest, map[string]string{"error": "请求格式错误"})
				return
			}
			device, err := store.SetProperty(deviceID, req.Field, req.Value)
			if err != nil {
				writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
				return
			}
			writeJSON(w, http.StatusOK, map[string]interface{}{
				"device": device,
				"action": "set_" + req.Field,
			})
			return
		}

		// GET /api/v1/devices/{id}/history
		if len(parts) == 2 && parts[1] == "history" {
			if r.Method != http.MethodGet {
				http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
				return
			}
			history := store.GetHistory(deviceID)
			writeJSON(w, http.StatusOK, map[string]interface{}{
				"device_id": deviceID,
				"history":   history,
			})
			return
		}

		// GET /api/v1/devices/{id}
		if r.Method != http.MethodGet {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}

		device := store.Get(deviceID)
		if device == nil {
			writeJSON(w, http.StatusNotFound, map[string]string{"error": fmt.Sprintf("设备 %s 不存在", deviceID)})
			return
		}
		writeJSON(w, http.StatusOK, map[string]interface{}{
			"device": device,
		})
	})

	// 健康检查
	mux.HandleFunc("/api/v1/health", func(w http.ResponseWriter, r *http.Request) {
		writeJSON(w, http.StatusOK, map[string]string{
			"status":  "ok",
			"service": "iot-debug-service",
		})
	})

	logger.Printf("🔌 IoT 调试服务启动在端口 %s", port)
	logger.Printf("   模拟设备数: %d", len(store.GetAll()))
	if err := http.ListenAndServe(":"+port, mux); err != nil {
		logger.Fatalf("服务启动失败: %v", err)
	}
}

func writeJSON(w http.ResponseWriter, status int, data interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(data)
}

func getEnv(key, fallback string) string {
	if v := os.Getenv(key); v != "" {
		return v
	}
	return fallback
}
