package subsession

import (
	"context"
	"fmt"
	"git.yeij.top/AskaEth/Cyrene/pkg/logger"
	"strings"
	"time"

	"git.yeij.top/AskaEth/Cyrene/ai-core/internal/model"
	"git.yeij.top/AskaEth/Cyrene/ai-core/internal/persona"
	"git.yeij.top/AskaEth/Cyrene/ai-core/internal/tools"
)

// IoTDeviceProvider IoT 设备查询接口
type IoTDeviceProvider interface {
	GetAllDevices(ctx context.Context) ([]tools.IoTDevice, error)
	GetDevice(ctx context.Context, id string) (*tools.IoTDevice, error)
	ToggleDevice(id string) error
	SetDeviceProperty(id string, field string, value interface{}) error
	GetDevicesForContext(ctx context.Context) []tools.IoTDevice
}

// IoTProvider IoT 控制子会话提供者
// 职责：处理 IoT 设备查询和控制请求
type IoTProvider struct {
	iotClient  IoTDeviceProvider
	personaDir string
}

// NewIoTProvider 创建 IoT 控制子会话提供者
func NewIoTProvider(iotClient IoTDeviceProvider, personaDir string) *IoTProvider {
	return &IoTProvider{
		iotClient:  iotClient,
		personaDir: personaDir,
	}
}

func (p *IoTProvider) Type() model.SubSessionType {
	return model.SubSessionIoT
}

func (p *IoTProvider) CanHandle(_ context.Context, intent *model.IntentResult, userMessage string) bool {
	// 意图分析明确需要 IoT
	if intent != nil && intent.NeedsIoT {
		return true
	}

	// 关键词触发（作为意图分析的补充）
	iotKeywords := []string{
		"灯", "空调", "窗帘", "电视", "设备", "开关",
		"打开", "关闭", "调到", "设置", "温度", "亮度",
		"传感器", "门锁", "插座", "风扇", "加湿器",
	}
	msgLower := strings.ToLower(userMessage)
	for _, kw := range iotKeywords {
		if strings.Contains(msgLower, kw) {
			return true
		}
	}

	return false
}

func (p *IoTProvider) Priority() int {
	return 3 // 低于 General 和 Memory
}

func (p *IoTProvider) Timeout() time.Duration {
	return 15 * time.Second
}

func (p *IoTProvider) CreateContext(ctx context.Context, params CreateContextParams) ([]model.LLMMessage, error) {
	messages := []model.LLMMessage{}

	// 获取当前设备状态
	var deviceStatusText string
	if p.iotClient != nil {
		devices := p.iotClient.GetDevicesForContext(ctx)
		if len(devices) > 0 {
			deviceStatusText = "当前设备状态：\n"
			for _, d := range devices {
				switch d.Type {
				case "light":
					if d.Status == "on" {
						deviceStatusText += fmt.Sprintf("- %s: 开启 (亮度%d%%, 颜色%s)\n", d.Name, d.Brightness, d.Color)
					} else {
						deviceStatusText += fmt.Sprintf("- %s: 关闭\n", d.Name)
					}
				case "ac":
					if d.Status == "on" {
						modeLabel := acModeLabel(d.Mode)
						deviceStatusText += fmt.Sprintf("- %s: 运行中 (%s %.0f°C)\n", d.Name, modeLabel, d.Temperature)
					} else {
						deviceStatusText += fmt.Sprintf("- %s: 关闭\n", d.Name)
					}
				case "curtain":
					if d.Status == "open" {
						deviceStatusText += fmt.Sprintf("- %s: 已打开\n", d.Name)
					} else {
						deviceStatusText += fmt.Sprintf("- %s: 已关闭\n", d.Name)
					}
				case "sensor":
					deviceStatusText += fmt.Sprintf("- %s: %.1f%s\n", d.Name, d.Value, d.Unit)
				default:
					deviceStatusText += fmt.Sprintf("- %s: %s\n", d.Name, d.Status)
				}
			}
		} else {
			deviceStatusText = "（暂无设备状态信息）"
		}
	} else {
		deviceStatusText = "（IoT 客户端未配置）"
	}

	// 加载人格配置
	trueName := "昔涟"
	personaPath := p.personaDir
	if personaPath == "" {
		personaPath = "./internal/persona"
	}
	loader, err := persona.NewLoader(personaPath)
	if err != nil {
		logger.Printf("[iot-provider] 加载人格配置失败: %v", err)
	}
	if loader != nil {
		if personaConfig, err := loader.Get("cyrene"); err == nil && personaConfig != nil {
			trueName = personaConfig.Identity.TrueName
		}
	}

	userName := params.Nickname
	if userName == "" {
		userName = params.UserID
	}

	systemPrompt := fmt.Sprintf(`你是%s，正在帮%s控制家里的智能设备。

## 你的能力
你可以通过以下方式帮%s控制设备：
- 查询设备当前状态
- 开关设备（灯、空调、窗帘等）
- 调节设备参数（亮度、温度、模式等）

## 回复风格
- 用俏皮可爱的语气告诉%s操作结果
- 简短自然，像小女友一样

## 当前设备状态
%s

## 用户请求
%s说：%s

## 你的任务
分析%s的请求，判断需要：
1. 只是查询设备状态？→ 直接基于上面的设备状态回答
2. 需要控制设备？→ 说明需要执行什么操作（开关/调节），并生成一个可爱的操作确认消息
3. 不需要IoT操作？→ 回复"无需IoT操作"

请用JSON格式输出：
{
  "action": "query" | "control" | "none",
  "device_id": "设备ID (如果需要操作)",
  "device_name": "设备名称",
  "operation": "toggle" | "set" | "query",
  "field": "属性名 (如 brightness, temperature)",
  "value": "属性值",
  "summary": "给用户的简短操作结果"
}`,
		trueName, userName,
		userName,
		userName,
		deviceStatusText,
		userName, params.UserMessage,
		userName,
	)

	messages = append(messages, model.LLMMessage{
		Role:    model.RoleSystem,
		Content: systemPrompt,
	})

	messages = append(messages, model.LLMMessage{
		Role:    model.RoleUser,
		Content: params.UserMessage,
	})

	return messages, nil
}

func (p *IoTProvider) Execute(ctx context.Context, subCtx []model.LLMMessage) (*model.SubSessionResult, error) {
	result := &model.SubSessionResult{
		Type:    model.SubSessionIoT,
		Summary: "（未执行 IoT 操作）",
	}

	userMessage := ""
	for i := len(subCtx) - 1; i >= 0; i-- {
		if subCtx[i].Role == model.RoleUser {
			userMessage = subCtx[i].Content
			break
		}
	}

	logger.Printf("[iot-provider] 📥 开始处理 IoT 子会话: userMessage=%s", truncateStr(userMessage, 80))

	if p.iotClient == nil {
		logger.Printf("[iot-provider] ⚠️ IoT 客户端未配置，无法控制设备")
		result.Summary = "（IoT 客户端未配置，无法控制设备）"
		return result, nil
	}

	devices := p.iotClient.GetDevicesForContext(ctx)
	logger.Printf("[iot-provider] 📋 获取到 %d 个设备用于匹配", len(devices))

	msgLower := strings.ToLower(userMessage)
	userName := extractUserName(subCtx)

	// 收集所有匹配的设备-操作对，支持多设备命令
	type deviceAction struct {
		dev       tools.IoTDevice
		operation string // "on" | "off" | "query"
	}
	var actions []deviceAction

	for _, dev := range devices {
		devNameLower := strings.ToLower(dev.Name)
		if !strings.Contains(msgLower, devNameLower) {
			continue
		}

		// 判断此设备的操作：先检查附近上下文，再回退到全文匹配
		devIdx := strings.Index(msgLower, devNameLower)
		contextStart := devIdx - 30
		if contextStart < 0 {
			contextStart = 0
		}
		contextEnd := devIdx + len(devNameLower) + 30
		if contextEnd > len(msgLower) {
			contextEnd = len(msgLower)
		}
		nearbyContext := msgLower[contextStart:contextEnd]

		hasOpen := strings.Contains(nearbyContext, "打开") || strings.Contains(nearbyContext, "开")
		hasClose := strings.Contains(nearbyContext, "关闭") || strings.Contains(nearbyContext, "关掉") || strings.Contains(nearbyContext, "关上") || strings.Contains(nearbyContext, "关")

		// 附近上下文不足以判断时，回退到全文搜索
		if !hasOpen && !hasClose {
			hasOpen = strings.Contains(msgLower, "打开")
			hasClose = strings.Contains(msgLower, "关闭") || strings.Contains(msgLower, "关掉") || strings.Contains(msgLower, "关上")
		}

		if hasOpen {
			actions = append(actions, deviceAction{dev: dev, operation: "on"})
		} else if hasClose {
			actions = append(actions, deviceAction{dev: dev, operation: "off"})
		} else {
			actions = append(actions, deviceAction{dev: dev, operation: "query"})
		}
	}

	// 如果没有匹配到具体设备，可能是查询所有设备状态
	if len(actions) == 0 {
		if strings.Contains(msgLower, "设备") && (strings.Contains(msgLower, "状态") || strings.Contains(msgLower, "怎么样") || strings.Contains(msgLower, "看看")) {
			if len(devices) > 0 {
				var sb strings.Builder
				sb.WriteString("家里设备状态：\n")
				for _, d := range devices {
					sb.WriteString(fmt.Sprintf("- %s: %s\n", d.Name, d.Status))
				}
				result.Summary = sb.String()
				result.Confidence = 0.7
				return result, nil
			}
		}
		logger.Printf("[iot-provider] ❌ 未匹配到 IoT 操作: userMessage=%s", truncateStr(userMessage, 80))
		result.Summary = "（未匹配到 IoT 操作）"
		result.Confidence = 0.5
		return result, nil
	}

	// 执行所有匹配到的操作
	var summaries []string
	var allToolCalls []model.ToolCallRecord
	executedCount := 0

	for _, action := range actions {
		switch action.operation {
		case "on":
			if action.dev.Status != "on" && action.dev.Status != "open" {
				if action.dev.Type == "curtain" {
					_ = p.iotClient.SetDeviceProperty(action.dev.ID, "status", "open")
				} else {
					_ = p.iotClient.ToggleDevice(action.dev.ID)
				}
				summaries = append(summaries, fmt.Sprintf("已帮%s打开%s♪", userName, action.dev.Name))
				allToolCalls = append(allToolCalls, model.ToolCallRecord{
					Name:      "iot_control",
					Arguments: map[string]any{"device_id": action.dev.ID, "operation": "toggle"},
					Result:    "success",
				})
				logger.Printf("[iot-subsession] 执行操作: 打开 %s (%s)", action.dev.Name, action.dev.ID)
				executedCount++
			} else {
				summaries = append(summaries, fmt.Sprintf("%s已经是打开状态啦~", action.dev.Name))
			}
		case "off":
			if action.dev.Status == "on" || action.dev.Status == "open" {
				if action.dev.Type == "curtain" {
					_ = p.iotClient.SetDeviceProperty(action.dev.ID, "status", "closed")
				} else {
					_ = p.iotClient.ToggleDevice(action.dev.ID)
				}
				summaries = append(summaries, fmt.Sprintf("已帮%s关闭%s~", userName, action.dev.Name))
				allToolCalls = append(allToolCalls, model.ToolCallRecord{
					Name:      "iot_control",
					Arguments: map[string]any{"device_id": action.dev.ID, "operation": "toggle"},
					Result:    "success",
				})
				logger.Printf("[iot-subsession] 执行操作: 关闭 %s (%s)", action.dev.Name, action.dev.ID)
				executedCount++
			} else {
				summaries = append(summaries, fmt.Sprintf("%s已经是关闭状态啦~", action.dev.Name))
			}
		case "query":
			deviceStatus := fmt.Sprintf("%s当前状态: %s", action.dev.Name, action.dev.Status)
			if action.dev.Type == "light" && action.dev.Status == "on" {
				deviceStatus += fmt.Sprintf(" (亮度%d%%, 颜色%s)", action.dev.Brightness, action.dev.Color)
			} else if action.dev.Type == "ac" && action.dev.Status == "on" {
				deviceStatus += fmt.Sprintf(" (模式%s, 温度%.0f°C)", action.dev.Mode, action.dev.Temperature)
			}
			summaries = append(summaries, deviceStatus)
		}
	}

	result.Summary = strings.Join(summaries, "; ")
	result.Confidence = 0.9
	if len(allToolCalls) > 0 {
		result.ToolCalls = allToolCalls
	}
	if executedCount == 0 {
		result.Confidence = 0.8
	}

	return result, nil
}

// extractUserName 从上下文中提取用户名
func extractUserName(subCtx []model.LLMMessage) string {
	for _, msg := range subCtx {
		if msg.Role == model.RoleSystem {
			// 尝试从系统提示词中提取称呼
			// 简单返回"你"
			break
		}
	}
	return "你"
}

func acModeLabel(mode string) string {
	switch mode {
	case "cool":
		return "制冷"
	case "heat":
		return "制热"
	case "auto":
		return "自动"
	default:
		return mode
	}
}

// truncateStr 截断字符串用于日志
func truncateStr(s string, maxLen int) string {
	runes := []rune(s)
	if len(runes) <= maxLen {
		return s
	}
	return string(runes[:maxLen]) + "..."
}

