#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import logging

from django.conf import settings
from django.core.cache import cache
from django.db import connection
from django.db.utils import OperationalError, ProgrammingError

from django_base_ai.utils.validator import CustomValidationError

# 配置日志
logger = logging.getLogger(__name__)

dispatch_db_type = getattr(settings, "DISPATCH_DB_TYPE", "memory")  # redis


def is_tenants_mode():
    """
    判断是否为租户模式
    :return:
    """
    is_tenant = hasattr(connection, "tenant") and connection.tenant.schema_name
    logger.debug(f"租户模式检查: {is_tenant}")
    return is_tenant


# ================================================= #
# ******************** 初始化 ******************** #
# ================================================= #
# 递归设置字典节点


def get_all_list(queryset=None, dictionary_value=None):
    from django_base_ai.system.models import Dictionary

    logger.debug(f"开始获取字典列表, dictionary_value: {dictionary_value}")
    if queryset is None:
        queryset = Dictionary.objects.filter(status=True, is_value=False)
    # 获取指定节点
    if dictionary_value is not None:
        queryset = queryset.filter(status=True, value=dictionary_value)
    data = []
    for instance in queryset:
        item = {
            "id": instance.id,
            "label": instance.label,
            "value": instance.value,
            "type": instance.type,
            "color": instance.color,
            "icon": instance.icon,
            "children": [],
        }
        _childs = Dictionary.objects.filter(parent=instance, status=True)
        if _childs:
            item["children"] = get_all_list(_childs, None)
        data.append(item)
    logger.debug(f"获取字典列表完成, 共 {len(data)} 条记录")
    return data


def _get_all_dictionary():
    try:
        from django_base_ai.system.models import Dictionary

        logger.debug("开始从数据库获取所有字典配置")
        queryset = Dictionary.objects.filter(status=True, is_value=False)
        data = []
        for instance in queryset:
            data.append(
                {
                    "id": instance.id,
                    "label": instance.label,
                    "value": instance.value,
                    "type": instance.type,
                    "color": instance.color,
                    "icon": instance.icon,
                    "remark": instance.remark,
                    "children": list(
                        Dictionary.objects.filter(parent=instance.id, status=True)
                        .filter(status=1)
                        .values("id", "label", "value", "type", "color", "icon", "remark")
                    ),
                }
            )
        result = {ele.get("value"): ele for ele in data}
        logger.info(f"从数据库获取字典配置完成, 共 {len(result)} 个字典项")
        return result
    except (ProgrammingError, OperationalError) as e:
        # 如果是表不存在的异常（例如在执行makemigrations时），返回空字典
        error_str = str(e)
        if "doesn't exist" in error_str or "Table" in error_str:
            logger.debug("数据库表尚未创建，返回空字典（可能正在执行迁移）")
            return {}
        raise
    except Exception as e:
        # 如果是 AppRegistryNotReady 异常，返回空字典
        error_str = str(e)
        if "AppRegistryNotReady" in str(type(e).__name__) or "Models aren't loaded yet" in error_str:
            logger.debug("Django 应用尚未初始化，返回空字典")
            return {}
        raise


def _get_all_system_config():
    try:
        data = {}
        from django_base_ai.system.models import SystemConfig

        logger.debug("开始从数据库获取所有系统配置")
        system_config_obj = (
            SystemConfig.objects.filter(parent_id__isnull=False)
            .values("parent__key", "key", "value", "form_item_type")
            .order_by("sort")
        )
        for system_config in system_config_obj:
            value = system_config.get("value", "")
            if value and system_config.get("form_item_type") == 7:
                value = value[0].get("url")
            data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = value
        logger.info(f"从数据库获取系统配置完成, 共 {len(data)} 个配置项")
        return data
    except (ProgrammingError, OperationalError) as e:
        # 如果是表不存在的异常（例如在执行makemigrations时），返回空字典
        error_str = str(e)
        if "doesn't exist" in error_str or "Table" in error_str:
            logger.debug("数据库表尚未创建，返回空字典（可能正在执行迁移）")
            return {}
        raise
    except Exception as e:
        # 如果是 AppRegistryNotReady 异常，返回空字典
        error_str = str(e)
        if "AppRegistryNotReady" in str(type(e).__name__) or "Models aren't loaded yet" in error_str:
            logger.debug("Django 应用尚未初始化，返回空字典")
            return {}
        logger.error(f"获取系统配置失败: {str(e)}", exc_info=True)
        return {}


def init_dictionary():
    """
    初始化字典配置
    :return:
    """
    logger.info(f"开始初始化字典配置, 存储类型: {dispatch_db_type}")
    try:
        if dispatch_db_type == "redis":
            logger.debug("使用Redis存储字典配置")
            dictionary_data = _get_all_dictionary()
            cache.set("init_dictionary", dictionary_data)
            logger.info("字典配置已存储到Redis缓存")
            return
        else:
            logger.debug("使用内存存储字典配置")
            settings.DICTIONARY_CONFIG = _get_all_dictionary()
            logger.info("字典配置已存储到内存")
    except Exception as e:
        # _get_all_dictionary 已经处理了表不存在的情况，这里只是做最后的容错
        error_str = str(e)
        if isinstance(e, (ProgrammingError, OperationalError)) and (
            "doesn't exist" in error_str or "Table" in error_str
        ):
            logger.debug("数据库表尚未创建，跳过字典配置初始化（可能正在执行迁移）")
            if dispatch_db_type == "redis":
                cache.set("init_dictionary", {})
            else:
                settings.DICTIONARY_CONFIG = {}
        else:
            logger.error(f"初始化字典配置失败: {str(e)}", exc_info=True)
    return


def init_system_config():
    """
    初始化系统配置
    :param name:
    :return:
    """
    logger.info(f"开始初始化系统配置, 存储类型: {dispatch_db_type}")
    try:
        if dispatch_db_type == "redis":
            logger.debug("使用Redis存储系统配置")
            system_config_data = _get_all_system_config()
            cache.set("init_system_config", system_config_data)
            logger.info("系统配置已存储到Redis缓存")
            return
        else:
            logger.debug("使用内存存储系统配置")
            settings.SYSTEM_CONFIG = _get_all_system_config()
            logger.info("系统配置已存储到内存")
    except Exception as e:
        # _get_all_system_config 已经处理了表不存在的情况，这里只是做最后的容错
        error_str = str(e)
        if isinstance(e, (ProgrammingError, OperationalError)) and (
            "doesn't exist" in error_str or "Table" in error_str
        ):
            logger.debug("数据库表尚未创建，跳过系统配置初始化（可能正在执行迁移）")
            if dispatch_db_type == "redis":
                cache.set("init_system_config", {})
            else:
                settings.SYSTEM_CONFIG = {}
        else:
            logger.error(f"初始化系统配置失败: {str(e)}", exc_info=True)
    return


def refresh_dictionary():
    """
    刷新字典配置
    :return:
    """
    try:
        logger.info("刷新字典配置")
        if dispatch_db_type == "redis":
            dictionary_data = _get_all_dictionary()
            cache.set("init_dictionary", dictionary_data)
            logger.info("字典配置已刷新到Redis缓存")
            return
        else:
            settings.DICTIONARY_CONFIG = _get_all_dictionary()
            logger.info("字典配置已刷新到内存")
    except Exception as e:
        # 如果是 AppRegistryNotReady 异常，静默失败
        error_str = str(e)
        if "AppRegistryNotReady" in str(type(e).__name__) or "Models aren't loaded yet" in error_str:
            logger.debug("Django 应用尚未初始化，跳过字典配置刷新")
            return
        raise


def refresh_system_config():
    """
    刷新系统配置
    :return:
    """
    logger.info("刷新系统配置")
    if dispatch_db_type == "redis":
        system_config_data = _get_all_system_config()
        cache.set("init_system_config", system_config_data)
        logger.info("系统配置已刷新到Redis缓存")
    else:
        settings.SYSTEM_CONFIG = _get_all_system_config()
        logger.info("系统配置已刷新到内存")


# ================================================= #
# ******************** 字典管理 ******************** #
# ================================================= #
def get_dictionary_config(schema_name=None):
    """
    获取字典所有配置
    :param schema_name: 对应字典配置的租户schema_name值
    :return:
    """
    logger.debug(f"开始获取字典配置, schema_name: {schema_name}")
    dictionary_config = {}
    if dispatch_db_type == "redis":
        init_dictionary_data = cache.get("init_dictionary")
        if not init_dictionary_data:
            logger.warning("Redis中没有找到字典配置，开始刷新")
            refresh_dictionary()
        result = cache.get("init_dictionary") or {}
        logger.debug(f"从Redis获取字典配置完成, 共 {len(result)} 个配置")
        return result
    if not settings.DICTIONARY_CONFIG:
        logger.warning("内存中没有字典配置，开始刷新")
        refresh_dictionary()
    else:
        dictionary_config = settings.DICTIONARY_CONFIG
    result = dictionary_config or {}
    logger.debug(f"从内存获取字典配置完成, 共 {len(result)} 个配置")
    return result


def get_dictionary_values(key, schema_name=None):
    """
    获取字典数据数组
    :param key: 对应字典配置的key值(字典编号)
    :param schema_name: 对应字典配置的租户schema_name值
    :return:
    """
    try:
        logger.debug(f"获取字典值, key: {key}, schema_name: {schema_name}")
        if dispatch_db_type == "redis":
            dictionary_config = cache.get("init_dictionary")
            if not dictionary_config:
                logger.debug("缓存中没有字典配置，开始刷新")
                refresh_dictionary()
                dictionary_config = cache.get("init_dictionary")
            result = dictionary_config.get(key)
            logger.debug(f"从Redis获取字典值完成, key: {key}, 结果存在: {result is not None}")
            return result
        dictionary_config = get_dictionary_config(schema_name)
        result = dictionary_config.get(key)
        logger.debug(f"从内存获取字典值完成, key: {key}, 结果存在: {result is not None}")
        return result
    except Exception as e:
        # 如果是 AppRegistryNotReady 异常，返回 None
        error_str = str(e)
        if "AppRegistryNotReady" in str(type(e).__name__) or "Models aren't loaded yet" in error_str:
            logger.debug(f"Django 应用尚未初始化，返回 None, key: {key}")
            return None
        raise


def get_dictionary_label(key, name, schema_name=None):
    """
    获取获取字典label值
    :param key: 字典管理中的key值(字典编号)
    :param name: 对应字典配置的value值
    :param schema_name: 对应字典配置的租户schema_name值
    :return:
    """
    logger.debug(f"获取字典标签, key: {key}, name: {name}, schema_name: {schema_name}")
    res = get_dictionary_values(key, schema_name) or {}
    children = res.get("children", [])
    for ele in children:
        if ele.get("value") == str(name):
            label = ele.get("label")
            logger.debug(f"找到匹配的字典标签: {label}")
            return label
    logger.debug(f"未找到匹配的字典标签, key: {key}, name: {name}")
    return ""


# ================================================= #
# ******************** 系统配置 ******************** #
# ================================================= #
def get_system_config(schema_name=None):
    """
    获取系统配置中所有配置
    1.只传父级的key，返回全部子级，{ "父级key.子级key" : "值" }
    2."父级key.子级key"，返回子级值
    :param schema_name: 对应字典配置的租户schema_name值
    :return:
    """
    logger.debug(f"开始获取系统配置, schema_name: {schema_name}")
    system_config = {}
    if dispatch_db_type == "redis":
        init_system_config_data = cache.get("init_system_config")
        if not init_system_config_data:
            logger.warning("Redis中没有找到系统配置，开始刷新")
            refresh_system_config()
        result = cache.get("init_system_config") or {}
        logger.debug(f"从Redis获取系统配置完成, 共 {len(result)} 个配置")
        return result
    if not settings.SYSTEM_CONFIG:
        logger.warning("内存中没有系统配置，开始刷新")
        refresh_system_config()
    else:
        system_config = settings.SYSTEM_CONFIG
    logger.debug(f"从内存获取系统配置完成, 共 {len(system_config)} 个配置")
    return system_config


def get_system_config_values(key, schema_name=None):
    """
    获取系统配置数据数组
    :param key: 对应系统配置的key值(字典编号)
    :param schema_name: 对应系统配置的租户schema_name值
    :return:
    """
    logger.debug(f"获取系统配置值, key: {key}, schema_name: {schema_name}")
    if dispatch_db_type == "redis":
        system_config = cache.get("init_system_config")
        if not system_config:
            logger.debug("缓存中没有系统配置，开始刷新")
            refresh_system_config()
            system_config = cache.get("init_system_config")
        result = system_config.get(key)
        logger.debug(f"从Redis获取系统配置值完成, key: {key}, 结果存在: {result is not None}")
        return result
    system_config = get_system_config(schema_name)
    result = system_config.get(key)
    logger.debug(f"从内存获取系统配置值完成, key: {key}, 结果存在: {result is not None}")
    return result


def get_system_config_values_to_dict(key, schema_name=None):
    """
    获取系统配置数据并转换为字典 **仅限于数组类型系统配置
    :param key: 对应系统配置的key值(字典编号)
    :param schema_name: 对应系统配置的租户schema_name值
    :return:
    """
    logger.debug(f"将系统配置转换为字典, key: {key}, schema_name: {schema_name}")
    values_dict = {}
    config_values = get_system_config_values(key, schema_name)
    if not isinstance(config_values, list):
        logger.error(f"系统配置值不是列表类型, key: {key}")
        raise CustomValidationError("该方式仅限于数组类型系统配置")
    for ele in get_system_config_values(key, schema_name):
        values_dict[ele.get("key")] = ele.get("value")
    logger.debug(f"系统配置转换为字典完成, key: {key}, 共 {len(values_dict)} 个条目")
    return values_dict


def get_system_config_label(key, name, schema_name=None):
    """
    获取获取系统配置label值
    :param key: 系统配置中的key值(字典编号)
    :param name: 对应系统配置的value值
    :param schema_name: 对应系统配置的租户schema_name值
    :return:
    """
    logger.debug(f"获取系统配置标签, key: {key}, name: {name}, schema_name: {schema_name}")
    children = get_system_config_values(key, schema_name) or []
    for ele in children:
        if ele.get("value") == str(name):
            label = ele.get("label")
            logger.debug(f"找到匹配的系统配置标签: {label}")
            return label
    logger.debug(f"未找到匹配的系统配置标签, key: {key}, name: {name}")
    return ""


# 获取字典数据-转化成tuple 用于字典choices
def get_dictionary_choices(dictionarg_key="") -> tuple:
    try:
        logger.debug(f"将字典数据转换为choices, key: {dictionarg_key}")
        dictionary_values = get_dictionary_values(dictionarg_key) or {}
        dictionary_children = dictionary_values.get("children", [])

        result = []
        for item in dictionary_children:
            value = item.get("value", 0)
            label = item.get("label", "未知")
            try:
                # 尝试转换为int
                int_value = int(value)
                result.append((int_value, label))
            except (ValueError, TypeError):
                # 如果无法转换为int，跳过该项
                logger.warning(f"字典值无法转换为int, key: {dictionarg_key}, value: {value}, 已跳过")
                continue

        result = tuple(result)
        logger.debug(f"字典choices转换完成, key: {dictionarg_key}, 共 {len(result)} 个选项")
        return result
    except Exception as e:
        # 如果是 AppRegistryNotReady 异常，静默返回空元组
        error_str = str(e)
        if "AppRegistryNotReady" in str(type(e).__name__) or "Models aren't loaded yet" in error_str:
            logger.debug(f"Django 应用尚未初始化，返回空元组, key: {dictionarg_key}")
            return ()
        logger.error(f"获取字典choices失败, key: {dictionarg_key}, 错误: {str(e)}", exc_info=True)
        return ()


# 获取导出excel下拉选择项
def get_import_dictionary_choices(dictionarg_key="") -> dict:
    try:
        logger.debug(f"获取导出excel下拉选择项, key: {dictionarg_key}")
        dictionary_values = get_dictionary_values(dictionarg_key) or {}
        dictionary_children = dictionary_values.get("children", [])
        choices_infos = {}
        for item in dictionary_children:
            value = item.get("value", 0)
            try:
                int_value = int(value)
                choices_infos.update({item.get("label", "未知"): int_value})
            except (ValueError, TypeError):
                logger.warning(f"字典值无法转换为int, key: {dictionarg_key}, value: {value}, 已跳过")
                continue
        logger.debug(f"导出下拉选择项获取完成, key: {dictionarg_key}, 共 {len(choices_infos)} 个选项")
        return choices_infos
    except Exception as e:
        logger.error(f"获取导出下拉选择项失败, key: {dictionarg_key}, 错误: {str(e)}", exc_info=True)
        return {}


# 通过key 获取字典 返回dict {value:label}
def get_dictionary_dict_result(dictionarg_key="") -> dict:
    try:
        logger.debug(f"获取字典字典结果, key: {dictionarg_key}")
        dictionary_values = get_dictionary_values(dictionarg_key) or {}
        dictionary_children = dictionary_values.get("children", [])
        dict_result = {}
        for item in dictionary_children:
            value = item.get("value", 0)
            label = item.get("label", "未知")
            dict_result.update({value: label})
        logger.debug(f"字典结果获取完成, key: {dictionarg_key}, 共 {len(dict_result)} 个条目")
        return dict_result
    except Exception as e:
        logger.error(f"获取字典结果失败, key: {dictionarg_key}, 错误: {str(e)}", exc_info=True)
        return {}


def get_all_tree_choice_recursive(dictionary_list: list, save_list: list) -> None:
    logger.debug(f"递归处理字典树, 当前级别: {len(dictionary_list)} 个节点")
    for i in dictionary_list:
        save_list.append({"label": i["label"], "value": i["value"]})
        if i["children"]:
            get_all_tree_choice_recursive(i["children"], save_list)
    return None


def get_dictionary_tree_all_choices(dictionarg_key="") -> dict:
    try:
        logger.debug(f"获取字典树所有选项, key: {dictionarg_key}")
        dictionarg_list = get_all_list(dictionary_value=dictionarg_key)
        save_list = []
        get_all_tree_choice_recursive(dictionarg_list, save_list)
        result = {i["value"]: i["label"] for i in save_list}
        logger.debug(f"字典树所有选项获取完成, key: {dictionarg_key}, 共 {len(result)} 个选项")
        return result
    except Exception as e:
        logger.error(f"获取字典树所有选项失败, key: {dictionarg_key}, 错误: {str(e)}", exc_info=True)
        print(e.args)
        return []
