from typing import Optional

from huibiao_framework.backend import CommonStatusCode
from huibiao_framework.backend.exception import BasicApiInnerException
from huibiao_framework.backend.status_code import (
    BasicApiId,
    BasicApiInnerErrorCode,
    BasicStatusCode,
)
from huibiao_framework.config.config import ErrorCodeConfig
import inspect
import sys


class ApiErrorCodeManage:
    """
    构建”5aaabb“错误码，aaa标书接口id，bb表示接口内部错误码
    """

    MAX_LEN = 8

    @classmethod
    def add_service_prefix(cls, v: int):
        """
        对于失败的状态码，添加服务号码前缀
        """
        v_str = str(v)
        if len(v_str) == cls.MAX_LEN:
            return v
        if (
            v is not None
            and v != CommonStatusCode.SUCCESS.code
            and ErrorCodeConfig.SERVICE_PREFIX
        ):
            v = int(f"{ErrorCodeConfig.SERVICE_PREFIX}{v_str}")
        return v

    @classmethod
    def set_error_code_prefix_env(cls, prefix: Optional[int] = None):
        """
        服务启动时执行这个函数
        也可以启动服务时通过环境变量ERROR_CODE_SERVICE_PREFIX指定服务前缀
        如果输入的prefix code不符合规则，则忽略，保持原来的6位
        """
        if prefix and 1 <= prefix <= 99:
            ErrorCodeConfig.SERVICE_PREFIX = prefix

    @classmethod
    def gen_api_error_code_msg(
        cls,
        api_id: BasicApiId,
        api_name: str = "",
        e: Optional[BasicApiInnerException | Exception] = None,
    ):
        """
        返回6位的错误码，表示内部错误
        """

        if e is None or not isinstance(e, BasicApiInnerException):
            inner_error_code = 0
            inner_error_msg = str(e)
        else:
            inner_error_code = e.code
            inner_error_msg = e.msg

        api_error_code = cls.__gen_error_code(api_id.value, inner_error_code)
        api_error_msg = f"接口[{api_name}]内部异常,报错:{inner_error_msg}"

        return api_error_code, api_error_msg

    @classmethod
    def __gen_error_code(cls, api_id: int, inner_error_code: int):
        return 500000 + api_id * 100 + inner_error_code

    @classmethod
    def scan_module_and_summary(cls, *list_module) -> list:
        """扫描模块中的ApiId和错误码枚举类"""
        api_id_dict: dict = {}
        api_err_code_info = []

        cls_list = []
        for m in list_module:
            cls_list.extend(
                [obj for name, obj in inspect.getmembers(m) if inspect.isclass(obj)]
            )

        for obj in set(cls_list):
            # 查找继承自BasicApiId的枚举类
            if issubclass(obj, BasicApiId) and obj != BasicApiId:
                for enum_member in obj:
                    api_id_dict[enum_member.value] = enum_member.name
                    api_err_code_info.append(
                        [
                            enum_member.value,
                            cls.__gen_error_code(enum_member.value, 0),
                            "",
                        ]
                    )

            # 查找继承自BasicApiInnerErrorCode的枚举类
            elif (
                issubclass(obj, BasicApiInnerErrorCode)
                and obj != BasicApiInnerErrorCode
                and hasattr(obj, "__api_id__")
            ):
                api_id_enum: BasicApiId = getattr(obj, "__api_id__")
                for enum_member in obj:
                    api_err_code_info.append(
                        [
                            api_id_enum.value,
                            cls.__gen_error_code(api_id_enum.value, enum_member.value),
                            enum_member.msg,
                        ]
                    )

        for idx, (api_code, _, _) in enumerate(api_err_code_info):
            api_err_code_info[idx][0] = api_id_dict[api_code]

        # 排序
        api_err_code_info.sort(key=lambda x: x[1])

        return api_err_code_info

    @classmethod
    def summary_module_api_error_code_markdown(cls, *list_module):
        """
        打印模块中的ApiId和错误码枚举类
        """
        result = cls.scan_module_and_summary(*list_module)

        print("| ApiName | ErrorCode | Message |")
        print("|--------|------------|---------|")
        for api_id, api_code, msg in result:
            print(f"| {api_id} | {api_code} | {msg} |")


class BasicCodeManage:
    __DEFAULT_MODULE = sys.modules["huibiao_framework.backend.status_code"]

    @classmethod
    def scan_module_and_summary(cls, *list_module) -> list:
        """扫描模块中BasicStatusCode枚举类及其子类"""
        if cls.__DEFAULT_MODULE not in list_module:
            list_module = list_module + (cls.__DEFAULT_MODULE,)

        result = []
        cls_list = []

        for m in list_module:
            cls_list.extend(
                [obj for name, obj in inspect.getmembers(m) if inspect.isclass(obj)]
            )

        for obj in set(cls_list):
            if issubclass(obj, BasicStatusCode) and obj != BasicApiId:
                for enum_member in obj:
                    result.append([enum_member.value, enum_member.msg])

        result.sort(key=lambda x: x[0])

        return result

    @classmethod
    def summary_error_code_markdown(cls, *list_module):
        """
        打印模块中的ApiId和错误码枚举类
        """
        result = cls.scan_module_and_summary(*list_module)

        print("| Code | Message |")
        print("|--------|------------|")
        for code, msg in result:
            print(f"| {code} | {msg} |")
