package tools

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"git.yeij.top/AskaEth/Cyrene/pkg/logger"
	"net/http"
	"os"
	"sync"
	"time"
)

// IoTDevice 设备结构体（与 IoT 调试服务的结构对应）
type IoTDevice struct {
	ID          string  `json:"id"`
	Name        string  `json:"name"`
	Type        string  `json:"type"`
	Status      string  `json:"status"`
	Brightness  int     `json:"brightness,omitempty"`
	Color       string  `json:"color,omitempty"`
	Temperature float64 `json:"temperature,omitempty"`
	Mode        string  `json:"mode,omitempty"`
	Position    int     `json:"position,omitempty"`
	Value       float64 `json:"value,omitempty"`
	Unit        string  `json:"unit,omitempty"`
	Battery     int     `json:"battery,omitempty"`
	LastUpdated string  `json:"last_updated"`
}

// IoTClient IoT 调试服务 HTTP 客户端
type IoTClient struct {
	baseURL string
	client  *http.Client

	// 缓存控制
	mu         sync.RWMutex
	cache      []IoTDevice
	cacheTime  time.Time
	cacheTTL   time.Duration
}

// NewIoTClient 创建 IoT 客户端
func NewIoTClient(baseURL string) *IoTClient {
	if baseURL == "" {
		// 向后兼容：优先使用 IOT_SERVICE_URL，回退到 IOT_DEBUG_SERVICE_URL
		baseURL = getEnv("IOT_SERVICE_URL", "")
		if baseURL == "" {
			baseURL = getEnv("IOT_DEBUG_SERVICE_URL", "http://localhost:8083")
		}
	}
	return &IoTClient{
		baseURL: baseURL,
		client: &http.Client{
			Timeout: 5 * time.Second,
		},
		cacheTTL: 60 * time.Second,
	}
}

// GetAllDevices 获取所有设备列表（带缓存）
func (c *IoTClient) GetAllDevices(ctx context.Context) ([]IoTDevice, error) {
	// 检查缓存
	c.mu.RLock()
	if c.cache != nil && time.Since(c.cacheTime) < c.cacheTTL {
		devices := make([]IoTDevice, len(c.cache))
		copy(devices, c.cache)
		c.mu.RUnlock()
		return devices, nil
	}
	c.mu.RUnlock()

	// 请求 API
	req, err := http.NewRequestWithContext(ctx, "GET", c.baseURL+"/api/v1/devices", nil)
	if err != nil {
		logger.Printf("[IoT客户端] 创建请求失败: %v", err)
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}

	resp, err := c.client.Do(req)
	if err != nil {
		logger.Printf("[IoT客户端] 请求失败: %v", err)
		return nil, fmt.Errorf("获取设备列表失败: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("获取设备列表返回状态码 %d", resp.StatusCode)
	}

	var result struct {
		Devices []IoTDevice `json:"devices"`
		Total   int         `json:"total"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("解析设备列表失败: %w", err)
	}

	// 更新缓存
	c.mu.Lock()
	c.cache = result.Devices
	c.cacheTime = time.Now()
	c.mu.Unlock()

	return result.Devices, nil
}

// GetDevice 获取单个设备详情
func (c *IoTClient) GetDevice(ctx context.Context, id string) (*IoTDevice, error) {
	req, err := http.NewRequestWithContext(ctx, "GET", c.baseURL+"/api/v1/devices/"+id, nil)
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("获取设备 %s 失败: %w", id, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNotFound {
		return nil, fmt.Errorf("设备 %s 不存在", id)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("获取设备 %s 返回状态码 %d", id, resp.StatusCode)
	}

	var result struct {
		Device IoTDevice `json:"device"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("解析设备信息失败: %w", err)
	}

	return &result.Device, nil
}

// ToggleDevice 切换设备开关状态
func (c *IoTClient) ToggleDevice(id string) error {
	logger.Printf("[IoT-client] 🔄 切换设备: id=%s, url=%s", id, c.baseURL+"/api/v1/devices/"+id+"/toggle")

	req, err := http.NewRequest(http.MethodPost, c.baseURL+"/api/v1/devices/"+id+"/toggle", nil)
	if err != nil {
		logger.Printf("[IoT-client] ❌ 创建切换请求失败: device=%s, err=%v", id, err)
		return fmt.Errorf("创建切换请求失败: %w", err)
	}

	resp, err := c.client.Do(req)
	if err != nil {
		logger.Printf("[IoT-client] ❌ 切换设备 HTTP 失败: device=%s, err=%v", id, err)
		return fmt.Errorf("切换设备 %s 失败: %w", id, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNotFound {
		logger.Printf("[IoT-client] ❌ 设备不存在: %s", id)
		return fmt.Errorf("设备 %s 不存在", id)
	}
	if resp.StatusCode != http.StatusOK {
		logger.Printf("[IoT-client] ❌ 切换设备返回非200: device=%s, status=%d", id, resp.StatusCode)
		return fmt.Errorf("切换设备 %s 返回状态码 %d", id, resp.StatusCode)
	}

	// 切换后清除缓存，确保下次查询获取最新状态
	c.mu.Lock()
	c.cache = nil
	c.mu.Unlock()

	logger.Printf("[IoT-client] ✅ 切换设备成功: %s", id)
	return nil
}

// SetDeviceProperty 设置设备属性（温度、亮度、位置、模式、颜色等）
func (c *IoTClient) SetDeviceProperty(id string, field string, value interface{}) error {
	logger.Printf("[IoT-client] 🔧 设置设备属性: device=%s, field=%s, value=%v, url=%s", id, field, value, c.baseURL+"/api/v1/devices/"+id+"/set")

	body, err := json.Marshal(map[string]interface{}{
		"field": field,
		"value": value,
	})
	if err != nil {
		logger.Printf("[IoT-client] ❌ 序列化请求失败: device=%s, err=%v", id, err)
		return fmt.Errorf("序列化请求失败: %w", err)
	}

	req, err := http.NewRequest(http.MethodPost, c.baseURL+"/api/v1/devices/"+id+"/set", nil)
	if err != nil {
		logger.Printf("[IoT-client] ❌ 创建设置请求失败: device=%s, err=%v", id, err)
		return fmt.Errorf("创建设置请求失败: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Body = io.NopCloser(bytes.NewReader(body))

	resp, err := c.client.Do(req)
	if err != nil {
		logger.Printf("[IoT-client] ❌ 设置设备属性 HTTP 失败: device=%s, field=%s, err=%v", id, field, err)
		return fmt.Errorf("设置设备 %s 属性失败: %w", id, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNotFound {
		logger.Printf("[IoT-client] ❌ 设备不存在: %s", id)
		return fmt.Errorf("设备 %s 不存在", id)
	}
	if resp.StatusCode != http.StatusOK {
		var errResp struct {
			Error string `json:"error"`
		}
		json.NewDecoder(resp.Body).Decode(&errResp)
		if errResp.Error != "" {
			logger.Printf("[IoT-client] ❌ 设置设备属性失败: device=%s, err=%s", id, errResp.Error)
			return fmt.Errorf("设置设备 %s 属性失败: %s", id, errResp.Error)
		}
		logger.Printf("[IoT-client] ❌ 设置设备属性返回非200: device=%s, status=%d", id, resp.StatusCode)
		return fmt.Errorf("设置设备 %s 属性返回状态码 %d", id, resp.StatusCode)
	}

	// 修改后清除缓存
	c.mu.Lock()
	c.cache = nil
	c.mu.Unlock()

	logger.Printf("[IoT-client] ✅ 设置设备属性成功: device=%s, field=%s, value=%v", id, field, value)
	return nil
}

// GetDevicesForContext 获取设备状态摘要（供上下文注入使用，失败不报错）
func (c *IoTClient) GetDevicesForContext(ctx context.Context) []IoTDevice {
	devices, err := c.GetAllDevices(ctx)
	if err != nil {
		logger.Printf("[IoT客户端] 获取设备状态摘要失败: %v", err)
		return nil
	}
	return devices
}

// InvalidateCache 使缓存失效
func (c *IoTClient) InvalidateCache() {
	c.mu.Lock()
	c.cache = nil
	c.mu.Unlock()
}

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