from typing import List, Dict, Any
from collections import defaultdict
import re
from .logger_config import get_logger

# 延迟初始化日志器，避免在导入时立即执行
logger = None

def _ensure_logger():
    """确保日志器已初始化"""
    global logger
    if logger is None:
        logger = get_logger(__name__)
    return logger


def process_device_data(data, enterprise_id):
    """
    处理设备数据，提取best_match并转换为指定格式

    Args:
        data (dict): 包含results和best_match的数据结构
        enterprise_id (str): 企业ID

    Returns:
        dict: 处理后的best_match数据，包含enterpriseId、entityId和command
        如果处理失败返回None
    """
    logger = _ensure_logger()
    logger.debug(f"开始处理设备数据，enterprise_id: {enterprise_id}")
    
    try:
        # 参数验证
        if not isinstance(data, dict):
            error_msg = "data参数必须是字典类型"
            logger.error(error_msg)
            raise ValueError(error_msg)

        if not enterprise_id:
            error_msg = "enterprise_id不能为空"
            logger.error(error_msg)
            raise ValueError(error_msg)

        # 检查数据是否包含best_match
        if "best_match" not in data:
            raise ValueError("数据中缺少best_match字段")

        best_match = data["best_match"]

        if not isinstance(best_match, dict):
            raise ValueError("best_match必须是字典类型")

        # 检查best_match是否包含device字段
        if "device" not in best_match:
            raise ValueError("best_match中缺少device字段")

        device_info = best_match["device"]

        if not isinstance(device_info, dict):
            raise ValueError("device_info必须是字典类型")

        # 检查device_info是否包含device和operation字段
        if "device" not in device_info:
            raise ValueError("device_info中缺少device字段")

        if "operation" not in device_info:
            raise ValueError("device_info中缺少operation字段")

        device_data = device_info["device"]
        operation_data = device_info["operation"]

        if not isinstance(device_data, dict) or not isinstance(operation_data, dict):
            raise ValueError("device和operation字段必须是字典类型")

        # 提取device的key作为entityId
        device_key = device_data.get("key", "")
        if not device_key:
            raise ValueError("device.key字段为空")

        # 提取operation的key作为command
        operation_key = operation_data.get("key", "")
        if not operation_key:
            raise ValueError("operation.key字段为空")

        # 构建返回结果
        processed_result = {
            "enterpriseId": enterprise_id,
            "entityId": device_key,
            "command": operation_key,
        }

        logger.info(f"设备数据处理成功: entityId={device_key}, command={operation_key}")
        logger.debug(f"处理结果: {processed_result}")
        return processed_result

    except Exception as e:
        logger.error(f"数据处理错误: {str(e)}", exc_info=True)
        return None


def process_device_data_safe(data, enterprise_id, default_result=None):
    """
    安全版本的数据处理方法，不会抛出异常

    Args:
        data (dict): 包含results和best_match的数据结构
        enterprise_id (str): 企业ID
        default_result (dict): 处理失败时的默认返回值

    Returns:
        dict: 处理后的best_match数据，处理失败时返回default_result
    """
    result = process_device_data(data, enterprise_id)
    return result if result is not None else default_result


def validate_device_data(data):
    """
    验证设备数据结构的完整性

    Args:
        data (dict): 要验证的数据

    Returns:
        tuple: (is_valid, error_message)
    """
    try:
        if not isinstance(data, dict):
            return False, "数据必须是字典类型"

        if "best_match" not in data:
            return False, "缺少best_match字段"

        best_match = data["best_match"]
        if not isinstance(best_match, dict):
            return False, "best_match必须是字典类型"

        if "device" not in best_match:
            return False, "best_match中缺少device字段"

        device_info = best_match["device"]
        if not isinstance(device_info, dict):
            return False, "device_info必须是字典类型"

        required_fields = ["device", "operation"]
        for field in required_fields:
            if field not in device_info:
                return False, f"device_info中缺少{field}字段"

            field_data = device_info[field]
            if not isinstance(field_data, dict):
                return False, f"{field}字段必须是字典类型"

            if "key" not in field_data or not field_data["key"]:
                return False, f"{field}.key字段不能为空"

        return True, "数据验证通过"

    except Exception as e:
        return False, f"验证过程中发生错误: {str(e)}"


def process_device_results(raw_data: List[List[Any]]) -> List[Dict[str, Any]]:
    """
    预处理数据，将原始数据转换为简化的数组对象格式
    如果 entityId 相同，则合并到一起

    Args:
        raw_data: 原始数据，格式为 [[entity, score], ...]

    Returns:
        处理后的数据数组，每个对象包含合并后的信息（不包含id和score_details字段）
    """
    logger = _ensure_logger()
    logger.debug(f"开始处理设备结果数据，输入数据条数: {len(raw_data) if raw_data else 0}")
    
    # 使用 entityId 作为分组键
    grouped_data = defaultdict(list)

    for item in raw_data:
        if len(item) >= 2:
            entity = item[0]
            score = item[1]
            
            logger.debug(f"处理项目: entity类型={type(entity)}, 包含keys={list(entity.keys()) if isinstance(entity, dict) else 'N/A'}")

            entityId = entity.get("device", {}).get("key", "")
            logger.debug(f"提取的entityId: '{entityId}'")
            
            # 如果entityId为空，跳过这个实体
            if not entityId:
                logger.warning(f"跳过entityId为空的实体: {entity}")
                continue

            # 创建简化的对象
            simplified_entity = {
                "location_key": entity.get("location", {}).get("key"),
                "location_desc": entity.get("location", {}).get("description"),
                "entityId": entity.get("device", {}).get("key"),
                "device_desc": entity.get("device", {}).get("description"),
                "command": entity.get("operation", {}).get("key"),
                "operation_desc": entity.get("operation", {}).get("description"),
                "operation_params": entity.get("operation_params", []),
                "score": score,
            }
            
            logger.debug(f"创建的简化实体: {simplified_entity}")
            grouped_data[entityId].append(simplified_entity)

    # 合并相同 entityId 的数据
    result = []
    logger.debug(f"grouped_data包含{len(grouped_data)}个组: {list(grouped_data.keys())}")
    
    for entityId, entities in grouped_data.items():
        logger.debug(f"处理entityId '{entityId}' 的 {len(entities)} 个实体")
        if len(entities) == 1:
            # 只有一个实体，直接添加
            result.append(entities[0])
            logger.debug(f"设备 {entityId} 只有一个实体，直接添加")
        else:
            # 多个实体需要合并
            merged_entity = merge_entities(entities)
            result.append(merged_entity)
            logger.debug(f"设备 {entityId} 有 {len(entities)} 个实体，已合并")

    logger.info(f"设备结果数据处理完成，输出数据条数: {len(result)}")
    logger.debug(f"最终结果: {result}")
    return result


def merge_entities(entities: List[Dict[str, Any]]) -> Dict[str, Any]:
    """
    合并相同 entityId 的多个实体

    Args:
        entities: 需要合并的实体列表

    Returns:
        合并后的实体
    """
    if not entities:
        return {}

    # 选择分数最高的作为主实体
    main_entity = max(entities, key=lambda x: x.get("score", 0))

    # 收集所有操作
    operations = []

    for entity in entities:
        operation_info = {
            "command": entity.get("command"),
            "operation_desc": entity.get("operation_desc"),
            "operation_params": entity.get("operation_params", []),
            "score": entity.get("score", 0),
        }
        operations.append(operation_info)

    # 创建合并后的实体
    merged_entity = {
        "location_key": main_entity.get("location_key"),
        "location_desc": main_entity.get("location_desc"),
        "entityId": main_entity.get("entityId"),
        "device_desc": main_entity.get("device_desc"),
        "operations": operations,  # 所有可能的操作
    }

    return merged_entity


def extract_space_entity_and_location(space_data: Dict[str, Any]) -> Dict[str, Any]:
    """
    从空间数据结构中提取 entityId 与 location。

    期望输入示例:
        {
            "spaceId": "46",
            "spaceAliasName": "爱易拍展厅；爱一拍展厅；爱一拍展区",
            "spaceName": "爱易拍展厅",
            ...
        }

    处理规则:
    - entityId = spaceId（转为字符串）
    - location 来自 spaceAliasName：
        - 若包含分隔符（例如 '；' 或 ';' 等），拆分并取第一个非空别名
        - 若不包含分隔符，则直接使用 spaceAliasName
        - 若 spaceAliasName 为空，回退到 spaceName；仍为空则返回空字符串

    Returns:
        {"entityId": str, "location": str}
    """
    logger = _ensure_logger()
    logger.debug(f"开始提取空间实体和位置信息: {space_data}")
    
    # entityId
    space_id = space_data.get("spaceId")
    entity_id = "" if space_id is None else str(space_id)
    logger.debug(f"提取的实体ID: {entity_id}")

    # location from alias
    alias_raw = space_data.get("spaceAliasName")
    alias_text = (
        alias_raw
        if isinstance(alias_raw, str)
        else (str(alias_raw) if alias_raw is not None else "")
    )

    chosen_location = alias_text.strip()

    if chosen_location:
        # 使用常见分隔符进行切分：中文分号、英文分号、中文逗号、英文逗号、竖线、斜杠
        parts = [
            p.strip()
            for p in re.split(r"[；;，,\|/]+", chosen_location)
            if p and p.strip()
        ]
        if parts:
            chosen_location = parts[0]
    else:
        # alias 为空则回退到 spaceName
        space_name = space_data.get("spaceName")
        chosen_location = (
            space_name.strip()
            if isinstance(space_name, str)
            else (str(space_name).strip() if space_name is not None else "")
        )

    result = {
        "entityId": entity_id,
        "location": chosen_location,
    }
    
    logger.info(f"空间实体和位置提取完成: entityId={entity_id}, location={chosen_location}")
    return result


def format_device_for_display(device: Dict[str, Any]) -> str:
    """
    将设备数据格式化为易读的描述文本
    用于展示给AI和用户，提升可读性和理解性
    
    Args:
        device: 设备数据字典，可能包含以下字段：
            - location_desc: 位置描述
            - device_desc: 设备描述
            - entityId: 设备唯一标识
            - operations: 操作列表（合并后的设备）
            或
            - command: 单个命令
            - operation_desc: 操作描述
            - operation_params: 操作参数
    
    Returns:
        格式化后的设备描述文本
    """
    logger = _ensure_logger()
    logger.debug(f"开始格式化设备显示信息: entityId={device.get('entityId', 'N/A')}")
    
    try:
        # 处理位置描述
        location = device.get('location_desc', '未知位置')
        if ';' in location or '；' in location:
            parts = re.split(r'[;；]', location)
            location = '（'.join(parts) + '）' if len(parts) > 1 else parts[0]
        
        # 处理设备类型描述
        device_type = device.get('device_desc', '未知设备')
        if ';' in device_type or '；' in device_type:
            parts = re.split(r'[;；]', device_type)
            device_type = '（'.join(parts) + '）' if len(parts) > 1 else parts[0]
        
        entity_id = device.get('entityId', '')
        
        formatted_text = f"""设备核心信息：
位置：{location}
设备类型：{device_type}
唯一标识（entityId）：{entity_id}

可执行操作："""
        
        # 判断是合并后的设备（有operations字段）还是单个操作设备
        if 'operations' in device:
            # 合并后的设备，包含多个操作
            operations = device.get('operations', [])
            for i, op in enumerate(operations, 1):
                cmd = op.get('command', '')
                desc = op.get('operation_desc', '').replace(';', ' / ').replace('；', ' / ')
                
                formatted_text += f"\n{i}. {desc}"
                formatted_text += f"\n   指令：{cmd}"
                
                params = op.get('operation_params', [])
                if params:
                    formatted_text += "\n   参数："
                    for param in params:
                        key = param.get('key', '')
                        description = param.get('description', '')
                        value = param.get('value', '')
                        formatted_text += f"\n   - {description}（{key}）：{value}"
                else:
                    formatted_text += "\n   参数：无"
        else:
            # 单个操作设备
            cmd = device.get('command', '')
            desc = device.get('operation_desc', '').replace(';', ' / ').replace('；', ' / ')
            
            formatted_text += f"\n1. {desc}"
            formatted_text += f"\n   指令：{cmd}"
            
            params = device.get('operation_params', [])
            if params:
                formatted_text += "\n   参数："
                for param in params:
                    key = param.get('key', '')
                    description = param.get('description', '')
                    value = param.get('value', '')
                    formatted_text += f"\n   - {description}（{key}）：{value}"
            else:
                formatted_text += "\n   参数：无"
        
        logger.debug(f"设备显示信息格式化完成: entityId={entity_id}")
        return formatted_text
        
    except Exception as e:
        logger.error(f"格式化设备显示信息时出错: {str(e)}", exc_info=True)
        return f"设备信息格式化失败: {str(e)}"


def format_devices_list(devices: List[Dict[str, Any]]) -> str:
    """
    格式化多个设备信息为易读的文本列表
    
    Args:
        devices: 设备数据列表
    
    Returns:
        格式化后的设备列表文本
    """
    logger = _ensure_logger()
    logger.debug(f"开始格式化设备列表，设备数量: {len(devices) if devices else 0}")
    
    if not devices:
        logger.warning("设备列表为空")
        return "未找到相关设备"
    
    try:
        formatted_list = []
        formatted_list.append(f"共找到 {len(devices)} 个匹配的设备\n")
        
        for idx, device in enumerate(devices, 1):
            if idx > 1:
                formatted_list.append("\n" + "-" * 40 + "\n")
            formatted_list.append(f"【设备 {idx}】")
            formatted_list.append(format_device_for_display(device))
        
        result = "\n".join(formatted_list)
        logger.info(f"设备列表格式化完成，设备数量: {len(devices)}")
        return result
        
    except Exception as e:
        logger.error(f"格式化设备列表时出错: {str(e)}", exc_info=True)
        return f"设备列表格式化失败: {str(e)}"


def format_device_for_display_simple(device: Dict[str, Any]) -> str:
    """
    将设备数据格式化为简化的描述文本（无装饰符号版本）
    适用于需要更简洁输出的场景
    
    Args:
        device: 设备数据字典
    
    Returns:
        格式化后的简化设备描述文本
    """
    logger = _ensure_logger()
    logger.debug(f"开始格式化设备简化显示信息: entityId={device.get('entityId', 'N/A')}")
    
    try:
        # 处理位置描述
        location = device.get('location_desc', '未知位置')
        if ';' in location or '；' in location:
            parts = re.split(r'[;；]', location)
            location = '（'.join(parts) + '）' if len(parts) > 1 else parts[0]
        
        # 处理设备类型描述
        device_type = device.get('device_desc', '未知设备')
        if ';' in device_type or '；' in device_type:
            parts = re.split(r'[;；]', device_type)
            device_type = '（'.join(parts) + '）' if len(parts) > 1 else parts[0]
        
        entity_id = device.get('entityId', '')
        
        formatted_text = f"""设备核心信息：
• 位置：{location}
• 设备类型：{device_type}
• 唯一标识（entityId）：{entity_id}

可执行操作："""
        
        # 判断是合并后的设备还是单个操作设备
        if 'operations' in device:
            operations = device.get('operations', [])
            for i, op in enumerate(operations, 1):
                cmd = op.get('command', '')
                desc = op.get('operation_desc', '').replace(';', ' / ').replace('；', ' / ')
                
                formatted_text += f"\n{i}. {desc}"
                formatted_text += f"\n   指令：{cmd}"
                
                params = op.get('operation_params', [])
                if params:
                    formatted_text += "\n   参数："
                    for param in params:
                        key = param.get('key', '')
                        description = param.get('description', '')
                        value = param.get('value', '')
                        formatted_text += f"\n   - {description}（{key}）：{value}"
                else:
                    formatted_text += "\n   参数：无"
        else:
            cmd = device.get('command', '')
            desc = device.get('operation_desc', '').replace(';', ' / ').replace('；', ' / ')
            
            formatted_text += f"\n1. {desc}"
            formatted_text += f"\n   指令：{cmd}"
            
            params = device.get('operation_params', [])
            if params:
                formatted_text += "\n   参数："
                for param in params:
                    key = param.get('key', '')
                    description = param.get('description', '')
                    value = param.get('value', '')
                    formatted_text += f"\n   - {description}（{key}）：{value}"
            else:
                formatted_text += "\n   参数：无"
        
        logger.debug(f"设备简化显示信息格式化完成: entityId={entity_id}")
        return formatted_text
        
    except Exception as e:
        logger.error(f"格式化设备简化显示信息时出错: {str(e)}", exc_info=True)
        return f"设备信息格式化失败: {str(e)}"


# 测试函数
def test_process_device_data():
    """测试数据处理函数"""
    logger = _ensure_logger()
    # 模拟输入数据
    test_data = {
        "results": [
            [
                {
                    "id": "32875964-00df-4b34-8e33-c47a722b8f7f",
                    "location": {"key": "lzwc", "description": "灵泽联创中心"},
                    "device": {
                        "key": "switch.zimi_cn_1144138206_dhkg01_on_p_2_1",
                        "description": "灵泽办公区过道吊灯  开关 按键",
                    },
                    "operation": {"key": "turn_on", "description": "开关"},
                    "operation_params": [],
                },
                0.34563739142066174,
                {
                    "exact_match": 0.25,
                    "word2vec_similarity": 0.5346393585205078,
                    "doc2vec_similarity": 0.004867201205343008,
                    "tfidf_similarity": 0.8217383432613271,
                    "combined_score": 0.34563739142066174,
                },
            ]
        ],
        "count": 1,
        "best_match": {
            "device": {
                "id": "32875964-00df-4b34-8e33-c47a722b8f7f",
                "location": {"key": "lzwc", "description": "灵泽联创中心"},
                "device": {
                    "key": "switch.zimi_cn_1144138206_dhkg01_on_p_2_1",
                    "description": "灵泽办公区过道吊灯  开关 按键",
                },
                "operation": {"key": "turn_on", "description": "开关"},
                "operation_params": [],
            },
            "score": 0.34563739142066174,
            "confidence": "低",
        },
    }

    enterprise_id = "1932095424144715777"

    logger.info("=== 测试数据处理功能 ===")

    # 1. 测试数据验证
    logger.info("1. 数据验证测试:")
    is_valid, message = validate_device_data(test_data)
    logger.info(f"数据验证结果: {is_valid}, 消息: {message}")

    # 2. 测试基本处理功能
    logger.info("2. 基本处理功能测试:")
    result = process_device_data(test_data, enterprise_id)
    logger.info(f"处理结果: {result}")

    # 3. 测试安全版本
    logger.info("3. 安全版本测试:")
    safe_result = process_device_data_safe(
        test_data, enterprise_id, {"error": "处理失败"}
    )
    logger.info(f"安全处理结果: {safe_result}")

    # 4. 测试错误情况
    logger.info("4. 错误情况测试:")
    # 测试空数据
    empty_result = process_device_data_safe({}, enterprise_id, {"error": "数据为空"})
    logger.info(f"空数据处理结果: {empty_result}")

    # 测试缺少字段的数据
    invalid_data = {"best_match": {"device": {}}}
    invalid_result = process_device_data_safe(
        invalid_data, enterprise_id, {"error": "数据格式错误"}
    )
    logger.info(f"无效数据处理结果: {invalid_result}")

    return result


def test_process_device_results():
    import json
    
    logger = _ensure_logger()
    
    # Load JSON data from file
    json_file_path = r"E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_iot\deviot.json"
    with open(json_file_path, 'r', encoding='utf-8') as f:
        raw_data = json.load(f)
    
    logger.info('Raw data loaded, processing...')
    result = process_device_results(raw_data)
    logger.info('Processed result:')
    for i, item in enumerate(result):
        logger.info(f"Item {i+1}: {item}")
    
    # Save results to output file
    output_file_path = r"E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_iot\output\output.json"
    with open(output_file_path, 'w', encoding='utf-8') as f:
        json.dump(result, f, ensure_ascii=False, indent=2)
    
    logger.info(f'Results saved to: {output_file_path}')
    
    return result

if __name__ == "__main__":
    # 测试代码只在直接运行此模块时执行，不在导入时执行
    # test_process_device_data()
    # test_process_device_results()  # 注释掉测试代码避免MCP服务器启动时执行
    pass
