import asyncio
import json
import time
from typing import List, Union

from .global_logger import logger
from . import prompt_template
from . import INVALID_ENTITY
from src.llm_models.utils_model import LLMRequest
from json_repair import repair_json


def _extract_json_from_text(text: str):
    # sourcery skip: assign-if-exp, extract-method
    """从文本中提取JSON数据的高容错方法"""
    if text is None:
        logger.error("输入文本为None")
        return []

    try:
        fixed_json = repair_json(text)
        if isinstance(fixed_json, str):
            parsed_json = json.loads(fixed_json)
        else:
            parsed_json = fixed_json

        # 如果是列表，直接返回
        if isinstance(parsed_json, list):
            return parsed_json

        # 如果是字典且只有一个项目，可能包装了列表
        if isinstance(parsed_json, dict):
            # 如果字典只有一个键，并且值是列表，返回那个列表
            if len(parsed_json) == 1:
                value = list(parsed_json.values())[0]
                if isinstance(value, list):
                    return value
            return parsed_json

        # 其他情况，尝试转换为列表
        logger.warning(f"解析的JSON不是预期格式: {type(parsed_json)}, 内容: {parsed_json}")
        return []

    except Exception as e:
        logger.error(f"JSON提取失败: {e}, 原始文本: {text[:100] if text else 'None'}...")
        return []


def _entity_extract(llm_req: LLMRequest, paragraph: str) -> List[str]:
    # sourcery skip: reintroduce-else, swap-if-else-branches, use-named-expression
    """对段落进行实体提取，返回提取出的实体列表（JSON格式）"""
    entity_extract_context = prompt_template.build_entity_extract_context(paragraph)

    # 使用 asyncio.run 来运行异步方法
    try:
        # 如果当前已有事件循环在运行，使用它
        loop = asyncio.get_running_loop()
        future = asyncio.run_coroutine_threadsafe(llm_req.generate_response_async(entity_extract_context), loop)
        response, _ = future.result()
    except RuntimeError:
        # 如果没有运行中的事件循环，直接使用 asyncio.run
        response, _ = asyncio.run(llm_req.generate_response_async(entity_extract_context))

    # 添加调试日志
    logger.debug(f"LLM返回的原始响应: {response}")

    entity_extract_result = _extract_json_from_text(response)

    # 检查返回的是否为有效的实体列表
    if not isinstance(entity_extract_result, list):
        if not isinstance(entity_extract_result, dict):
            raise ValueError(f"实体提取结果格式错误，期望列表但得到: {type(entity_extract_result)}")

        # 尝试常见的键名
        for key in ["entities", "result", "data", "items"]:
            if key in entity_extract_result and isinstance(entity_extract_result[key], list):
                entity_extract_result = entity_extract_result[key]
                break
        else:
            # 如果找不到合适的列表，抛出异常
            raise ValueError(f"实体提取结果格式错误，期望列表但得到: {type(entity_extract_result)}")
    # 过滤无效实体
    entity_extract_result = [
        entity
        for entity in entity_extract_result
        if (entity is not None) and (entity != "") and (entity not in INVALID_ENTITY)
    ]

    if not entity_extract_result:
        raise ValueError("实体提取结果为空")

    return entity_extract_result


def _rdf_triple_extract(llm_req: LLMRequest, paragraph: str, entities: list) -> List[List[str]]:
    """对段落进行实体提取，返回提取出的实体列表（JSON格式）"""
    rdf_extract_context = prompt_template.build_rdf_triple_extract_context(
        paragraph, entities=json.dumps(entities, ensure_ascii=False)
    )

    # 使用 asyncio.run 来运行异步方法
    try:
        # 如果当前已有事件循环在运行，使用它
        loop = asyncio.get_running_loop()
        future = asyncio.run_coroutine_threadsafe(llm_req.generate_response_async(rdf_extract_context), loop)
        response, _ = future.result()
    except RuntimeError:
        # 如果没有运行中的事件循环，直接使用 asyncio.run
        response, _ = asyncio.run(llm_req.generate_response_async(rdf_extract_context))

    # 添加调试日志
    logger.debug(f"RDF LLM返回的原始响应: {response}")

    rdf_triple_result = _extract_json_from_text(response)

    # 检查返回的是否为有效的三元组列表
    if not isinstance(rdf_triple_result, list):
        if not isinstance(rdf_triple_result, dict):
            raise ValueError(f"RDF三元组提取结果格式错误，期望列表但得到: {type(rdf_triple_result)}")

        # 尝试常见的键名
        for key in ["triples", "result", "data", "items"]:
            if key in rdf_triple_result and isinstance(rdf_triple_result[key], list):
                rdf_triple_result = rdf_triple_result[key]
                break
        else:
            # 如果找不到合适的列表，抛出异常
            raise ValueError(f"RDF三元组提取结果格式错误，期望列表但得到: {type(rdf_triple_result)}")
    # 验证三元组格式
    for triple in rdf_triple_result:
        if (
            not isinstance(triple, list)
            or len(triple) != 3
            or (triple[0] is None or triple[1] is None or triple[2] is None)
            or "" in triple
        ):
            raise ValueError("RDF提取结果格式错误")

    return rdf_triple_result


def info_extract_from_str(
    llm_client_for_ner: LLMRequest, llm_client_for_rdf: LLMRequest, paragraph: str
) -> Union[tuple[None, None], tuple[list[str], list[list[str]]]]:
    try_count = 0
    while True:
        try:
            entity_extract_result = _entity_extract(llm_client_for_ner, paragraph)
            break
        except Exception as e:
            logger.warning(f"实体提取失败，错误信息：{e}")
            try_count += 1
            if try_count < 3:
                logger.warning("将于5秒后重试")
                time.sleep(5)
            else:
                logger.error("实体提取失败，已达最大重试次数")
                return None, None

    try_count = 0
    while True:
        try:
            rdf_triple_extract_result = _rdf_triple_extract(llm_client_for_rdf, paragraph, entity_extract_result)
            break
        except Exception as e:
            logger.warning(f"实体提取失败，错误信息：{e}")
            try_count += 1
            if try_count < 3:
                logger.warning("将于5秒后重试")
                time.sleep(5)
            else:
                logger.error("实体提取失败，已达最大重试次数")
                return None, None

    return entity_extract_result, rdf_triple_extract_result
