package tools

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
)

// IoTControlTool IoT 设备控制工具
type IoTControlTool struct {
	iotClient *IoTClient
}

// NewIoTControlTool 创建 IoT 控制工具
func NewIoTControlTool(iotClient *IoTClient) *IoTControlTool {
	return &IoTControlTool{iotClient: iotClient}
}

// Definition 返回工具定义
func (t *IoTControlTool) Definition() ToolDefinition {
	return ToolDefinition{
		Name: "iot_control",
		Description: "【仅当开拓者明确要求控制设备时才使用此工具】控制家中智能设备。可以开关灯光、空调、窗帘、门锁等设备，也可以调节温度、亮度、位置、模式、颜色等属性。" +
			"\n⚠️ 重要约束：" +
			"\n  - 不要在开拓者只是询问设备状态时调用此工具（查询设备请用 iot_query）" +
			"\n  - 不要自行决定执行操作，必须等开拓者明确说出「打开」「关闭」「调到」「设置」等控制指令" +
			"\n  - 不要因为之前对话中提到过某个设备就主动控制它" +
			"\n支持的操作：toggle（切换开关状态）、turn_on（打开设备）、turn_off（关闭设备）、" +
			"set_temperature（设置空调温度，需要 value 参数，单位°C）、" +
			"set_brightness（设置灯光亮度，需要 value 参数，0-100）、" +
			"set_position（设置窗帘位置，需要 value 参数，0-100，0=关闭 100=全开）、" +
			"set_mode（设置空调模式，需要 value 参数，可选值: cool/heat/auto）、" +
			"set_color（设置灯光颜色，需要 value 参数，可选值: warm_white/cool_white/colorful）",
		Parameters: map[string]interface{}{
			"type": "object",
			"properties": map[string]interface{}{
				"device_id": map[string]interface{}{
					"type":        "string",
					"description": "要控制的设备ID。可选值: light-livingroom, light-bedroom, ac-livingroom, ac-bedroom, curtain-livingroom, lock-door",
				},
				"action": map[string]interface{}{
					"type":        "string",
					"enum":        []string{"toggle", "turn_on", "turn_off", "set_temperature", "set_brightness", "set_position", "set_mode", "set_color"},
					"description": "要执行的操作。toggle：切换开关状态；turn_on：打开设备；turn_off：关闭设备；set_temperature：设置空调温度（需配合value参数）；set_brightness：设置灯光亮度（需配合value参数）；set_position：设置窗帘位置（需配合value参数）；set_mode：设置空调模式（需配合value参数）；set_color：设置灯光颜色（需配合value参数）",
				},
				"value": map[string]interface{}{
					"type":        "number",
					"description": "操作的值。set_temperature 时表示目标温度（°C），set_brightness 时表示亮度百分比（0-100），set_position 时表示窗帘开合程度（0-100）。action 为 set_temperature/set_brightness/set_position 时必须提供。set_mode 时为字符串（cool/heat/auto），set_color 时为字符串（warm_white/cool_white/colorful）",
				},
			},
			"required": []string{"device_id", "action"},
		},
	}
}

// normalizeAction 标准化 action 参数，支持中文别名、power 参数等
func normalizeAction(arguments map[string]interface{}) string {
	action, _ := arguments["action"].(string)

	// 如果 action 为空，检查 power/status 参数
	if action == "" {
		// power 参数: "off"/"关"/"关闭" → turn_off, "on"/"开"/"打开" → turn_on
		if pv, ok := arguments["power"]; ok {
			switch v := pv.(type) {
			case string:
				switch strings.ToLower(strings.TrimSpace(v)) {
				case "off", "false", "关", "关闭":
					return "turn_off"
				case "on", "true", "开", "打开", "开启":
					return "turn_on"
				}
			case bool:
				if !v {
					return "turn_off"
				}
				return "turn_on"
			}
		}
		// status 参数同理
		if sv, ok := arguments["status"]; ok {
			switch v := sv.(type) {
			case string:
				switch strings.ToLower(strings.TrimSpace(v)) {
				case "off", "false", "关", "关闭":
					return "turn_off"
				case "on", "true", "开", "打开", "开启":
					return "turn_on"
				}
			case bool:
				if !v {
					return "turn_off"
				}
				return "turn_on"
			}
		}
		// 默认 toggle
		return "toggle"
	}

	// 标准化中文 action 名
	switch strings.ToLower(strings.TrimSpace(action)) {
	case "打开", "开启", "开":
		return "turn_on"
	case "关闭", "关":
		return "turn_off"
	case "切换":
		return "toggle"
	case "设置温度", "调温度", "set_temp":
		return "set_temperature"
	case "设置亮度", "调亮度", "set_light":
		return "set_brightness"
	case "设置位置", "调位置":
		return "set_position"
	case "设置模式", "调模式", "切换模式":
		return "set_mode"
	case "设置颜色", "调颜色", "换颜色":
		return "set_color"
	}

	return action
}

// Execute 执行设备控制
func (t *IoTControlTool) Execute(ctx context.Context, arguments map[string]interface{}) (*ToolResult, error) {
	if t.iotClient == nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    "IoT 客户端未初始化",
		}, nil
	}

	// 参数别名：entity_id → device_id
	deviceID, _ := arguments["device_id"].(string)
	if deviceID == "" {
		deviceID, _ = arguments["entity_id"].(string)
	}

	action := normalizeAction(arguments)

	if deviceID == "" {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    "缺少设备ID（请使用 device_id 参数）",
		}, nil
	}

	// 先获取设备名用于友好的返回消息（失败不影响后续流程）
	deviceName := deviceID
	if dev, err := t.iotClient.GetDevice(ctx, deviceID); err == nil {
		deviceName = dev.Name
	}

	// 处理属性设置类操作
	switch action {
	case "set_temperature":
		return t.handleSetTemperature(ctx, deviceID, arguments)
	case "set_brightness":
		return t.handleSetBrightness(ctx, deviceID, arguments)
	case "set_position":
		return t.handleSetPosition(ctx, deviceID, arguments)
	case "set_mode":
		return t.handleSetMode(ctx, deviceID, arguments)
	case "set_color":
		return t.handleSetColor(ctx, deviceID, arguments)
	case "turn_off":
		// 声明式关闭：使用 SetDeviceProperty status/off 而非 toggle
		// 即使设备已经关闭，SetProperty 也会幂等处理
		if err := t.iotClient.SetDeviceProperty(deviceID, "status", "off"); err != nil {
			return &ToolResult{
				ToolName: "iot_control",
				Success:  false,
				Error:    fmt.Sprintf("关闭设备失败: %v", err),
			}, nil
		}
		return &ToolResult{
			ToolName: "iot_control",
			Success:  true,
			Data:     fmt.Sprintf("已关闭设备: %s", deviceName),
		}, nil
	case "turn_on":
		// 声明式打开：使用 SetDeviceProperty status/on 而非 toggle
		if err := t.iotClient.SetDeviceProperty(deviceID, "status", "on"); err != nil {
			return &ToolResult{
				ToolName: "iot_control",
				Success:  false,
				Error:    fmt.Sprintf("打开设备失败: %v", err),
			}, nil
		}
		return &ToolResult{
			ToolName: "iot_control",
			Success:  true,
			Data:     fmt.Sprintf("已打开设备: %s", deviceName),
		}, nil
	default: // "toggle"
		if err := t.iotClient.ToggleDevice(deviceID); err != nil {
			return &ToolResult{
				ToolName: "iot_control",
				Success:  false,
				Error:    fmt.Sprintf("操作设备失败: %v", err),
			}, nil
		}

		// 获取切换后的状态
		updatedDevice, err := t.iotClient.GetDevice(ctx, deviceID)
		if err != nil {
			return &ToolResult{
				ToolName: "iot_control",
				Success:  true,
				Data:     fmt.Sprintf("已成功切换设备 %s 的状态。", deviceName),
			}, nil
		}

		return &ToolResult{
			ToolName: "iot_control",
			Success:  true,
			Data:     fmt.Sprintf("已成功操作设备: %s\n当前状态: %s", updatedDevice.Name, formatDeviceLine(*updatedDevice)),
		}, nil
	}
}

// extractValue 从 arguments 中提取 value 参数（支持 value/Value 及数字/字符串类型）
func extractValue(arguments map[string]interface{}) interface{} {
	if v, ok := arguments["value"]; ok {
		return v
	}
	return nil
}

// handleSetTemperature 处理设置温度
func (t *IoTControlTool) handleSetTemperature(ctx context.Context, deviceID string, arguments map[string]interface{}) (*ToolResult, error) {
	val := extractValue(arguments)
	if val == nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    "缺少 value 参数，请指定目标温度（如 24）",
		}, nil
	}

	// 先获取当前设备信息
	currentDevice, err := t.iotClient.GetDevice(ctx, deviceID)
	if err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("获取设备状态失败: %v", err),
		}, nil
	}

	temperature, ok := toFloat64(val)
	if !ok {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("温度值无效: %v", val),
		}, nil
	}

	if err := t.iotClient.SetDeviceProperty(deviceID, "temperature", temperature); err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("设置温度失败: %v", err),
		}, nil
	}

	return &ToolResult{
		ToolName: "iot_control",
		Success:  true,
		Data:     fmt.Sprintf("已将 %s 温度从 %.1f°C 调整为 %.1f°C", currentDevice.Name, currentDevice.Temperature, temperature),
	}, nil
}

// handleSetBrightness 处理设置亮度
func (t *IoTControlTool) handleSetBrightness(ctx context.Context, deviceID string, arguments map[string]interface{}) (*ToolResult, error) {
	val := extractValue(arguments)
	if val == nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    "缺少 value 参数，请指定亮度值（0-100）",
		}, nil
	}

	// 先获取当前设备信息
	currentDevice, err := t.iotClient.GetDevice(ctx, deviceID)
	if err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("获取设备状态失败: %v", err),
		}, nil
	}

	brightness, ok := toFloat64(val)
	if !ok {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("亮度值无效: %v", val),
		}, nil
	}

	if err := t.iotClient.SetDeviceProperty(deviceID, "brightness", brightness); err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("设置亮度失败: %v", err),
		}, nil
	}

	return &ToolResult{
		ToolName: "iot_control",
		Success:  true,
		Data:     fmt.Sprintf("已将 %s 亮度调整为 %d%%", currentDevice.Name, int(brightness)),
	}, nil
}

// handleSetPosition 处理设置窗帘位置
func (t *IoTControlTool) handleSetPosition(ctx context.Context, deviceID string, arguments map[string]interface{}) (*ToolResult, error) {
	val := extractValue(arguments)
	if val == nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    "缺少 value 参数，请指定位置值（0=关闭, 100=全开）",
		}, nil
	}

	currentDevice, err := t.iotClient.GetDevice(ctx, deviceID)
	if err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("获取设备状态失败: %v", err),
		}, nil
	}

	position, ok := toFloat64(val)
	if !ok {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("位置值无效: %v", val),
		}, nil
	}

	if err := t.iotClient.SetDeviceProperty(deviceID, "position", position); err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("设置窗帘位置失败: %v", err),
		}, nil
	}

	return &ToolResult{
		ToolName: "iot_control",
		Success:  true,
		Data:     fmt.Sprintf("已将 %s 窗帘调整为 %d%%", currentDevice.Name, int(position)),
	}, nil
}

// handleSetMode 处理设置空调模式
func (t *IoTControlTool) handleSetMode(ctx context.Context, deviceID string, arguments map[string]interface{}) (*ToolResult, error) {
	val := extractValue(arguments)
	if val == nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    "缺少 value 参数，请指定模式（cool/heat/auto）",
		}, nil
	}

	mode, ok := val.(string)
	if !ok {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("模式值无效: %v", val),
		}, nil
	}

	currentDevice, err := t.iotClient.GetDevice(ctx, deviceID)
	if err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("获取设备状态失败: %v", err),
		}, nil
	}

	if err := t.iotClient.SetDeviceProperty(deviceID, "mode", mode); err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("设置模式失败: %v", err),
		}, nil
	}

	return &ToolResult{
		ToolName: "iot_control",
		Success:  true,
		Data:     fmt.Sprintf("已将 %s 模式切换为 %s", currentDevice.Name, mode),
	}, nil
}

// handleSetColor 处理设置灯光颜色
func (t *IoTControlTool) handleSetColor(ctx context.Context, deviceID string, arguments map[string]interface{}) (*ToolResult, error) {
	val := extractValue(arguments)
	if val == nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    "缺少 value 参数，请指定颜色（warm_white/cool_white/colorful）",
		}, nil
	}

	color, ok := val.(string)
	if !ok {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("颜色值无效: %v", val),
		}, nil
	}

	currentDevice, err := t.iotClient.GetDevice(ctx, deviceID)
	if err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("获取设备状态失败: %v", err),
		}, nil
	}

	if err := t.iotClient.SetDeviceProperty(deviceID, "color", color); err != nil {
		return &ToolResult{
			ToolName: "iot_control",
			Success:  false,
			Error:    fmt.Sprintf("设置颜色失败: %v", err),
		}, nil
	}

	return &ToolResult{
		ToolName: "iot_control",
		Success:  true,
		Data:     fmt.Sprintf("已将 %s 灯光颜色切换为 %s", currentDevice.Name, color),
	}, nil
}

// 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
	}
}
