# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
import argparse
import json
import logging
import os
from pathlib import Path
from typing import Dict, Any


DEFAULT_TEMP_PATH = 'temp/opt/bmc/apps/mbd_interface'


class MDBMarkdownGenerator:
    def __init__(self, mdb_root: str, interface_type: str):
        self.mdb_root = mdb_root
        self.interface_type = interface_type
        self.md_content = []

    # 解析类型定义
    @staticmethod
    def _resolve_type(definition: Dict) -> str:
        if definition.get('baseType') == 'Dictionary':
            return definition.get('$ref', '').split('#/defs/')[-1]
        return definition.get('baseType', 'unknown')

    # 生成并保存文档
    def generate(self, output_dir: str):
        mdbtree = self._read_json_files()
        os.makedirs(output_dir, exist_ok=True)

        for interface_name, interface_def in sorted(mdbtree.items()):
            self.md_content.append(f"# {interface_name}")

            # 生成属性章节
            props_section = self._generate_properties_table(interface_def.get('properties', {}))
            if props_section:
                self.md_content.append(props_section)

            # 生成方法章节
            methods_section = self._generate_methods_section(interface_def.get('methods', {}))
            if methods_section:
                self.md_content.append(methods_section)

            # 生成自定义类型章节
            defs_section = self._generate_defs_section(interface_def.get('defs', {}))
            if defs_section:
                self.md_content.append(defs_section)

        # 写入文件
        output_path = Path(output_dir) / f'{self.interface_type}_interface.md'
        with output_path.open('w', encoding='utf-8') as f:
            f.write('\n\n'.join(self.md_content))
        logging.info(f'文档已生成“{output_path}')

    # 读取所有接口JSON文件
    def _read_json_files(self) -> Dict[str, Any]:
        mdbtree = {}
        json_dir = Path(self.mdb_root) / 'json' / 'intf' / 'mdb' / 'bmc' / self.interface_type
        for json_path in json_dir.rglob('*.json'):
            try:
                with json_path.open(encoding='utf-8') as f:
                    content = json.load(f)
            except (IOError, json.JSONDecodeError) as e:
                logging.warning(f"读取文件 {json_path} 失败 - {str(e)}")
                continue

            for key, value in content.items():
                if f'bmc.{self.interface_type}' in key:
                    mdbtree[key] = value
                    if 'defs' in content:
                        mdbtree[key]['defs'] = content['defs']
        return mdbtree

    # 生成属性表格
    def _generate_properties_table(self, properties: Dict[str, Any]) -> str:
        if not properties:
            return ''
        table = [
            '## 属性',
            '| 属性名 | 类型 | 可读写 | 信号通知 | 描述 |',
            "|-------|------|-------|---------|------|"
        ]

        for prop_name, prop_def in properties.items():
            prop_type = self._resolve_type(prop_def)
            read_write = "只读" if prop_def.get('readOnly', False) else "读写"
            signal = "变更广播" if prop_def.get('options', {}).get('emitChangedSignal', True) else "无"
            description = prop_def.get('description', '').replace('\n', ' ')

            table.append(
                f" | `{prop_name}` | `{prop_type}` |{read_write} | {signal} | {description} |"
            )
        return '\n'.join(table)

    # 生成单个方法文档
    def _generate_method_section(self, method_def: Dict[str, Any]) -> str:
        sections = []
        if 'description' in method_def:
            sections.append(f'\n**描述：** {method_def["description"]}')

        # 处理输入参数
        if 'req' in method_def and method_def['req']:
            input_table = [
                "\n**输入参数：**",
                "| 参数名 | 类型 | 描述 |",
                "|-------|-----|-----|"
            ]
            for param_name, param_def in method_def['req'].items():
                param_type = self._resolve_type(param_def)
                description = param_def.get('description', '').replace('\n', ' ').replace('{', '[').replace('}', ']')
                input_table.append(f"| `{param_name}` | `{param_type}` |{description} |")
            sections.append('\n'.join(input_table))

        # 处理输出参数
        if 'rsp' in method_def and method_def['rsp']:
            output_table = [
                "\n**输出参数：**",
                "| 参数名 | 类型 | 描述 |",
                "|-------|-----|-----|"
            ]
            for param_name, param_def in method_def['rsp'].items():
                param_type = self._resolve_type(param_def)
                description = param_def.get('description', '').replace('\n', ' ').replace('{', '[').replace('}', ']')
                output_table.append(f"| `{param_name}` | `{param_type}` |{description} |")
            sections.append('\n'.join(output_table))

        return '\n'.join(sections)

    # 生成方法文档
    def _generate_methods_section(self, methods: Dict[str, Any]) -> str:
        if not methods:
            return ''

        sections = ["## 方法"]
        for method_name, method_def in methods.items():
            sections.append(f"### `{method_name}`\n{self._generate_method_section(method_def)}")
        return '\n'.join(sections)

    #生成自定义类型文档
    def _generate_defs_section(self, defs: Dict[str, Any]) -> str:
        if not defs:
            return ''

        sections = ["## 自定义类型"]
        for type_name, type_def in defs.items():
            # 判断是否为枚举类型（即所有字段皆为整数）
            is_enum = all(isinstance(value, int) for value in type_def.values())

            # 根据类型决定表格标题和列名
            title_suffix = "枚举" if is_enum else "结构"
            headers = ("数值", "描述") if is_enum else ("类型", "描述")
            type_table = [
                f"\n**`{type_name}`** {title_suffix}：",
                "|字段名|类型| {} |".format(headers[0] if is_enum else headers[1]),
                "|-------|-----|-----|"
            ]

            # 填充表格内容
            for field_name, field_value in type_def.items():
                if is_enum:
                    # 枚举类型
                    type_table.append(f"| {field_name} | Enum |{field_value} |")
                else:
                    if isinstance(field_value, dict):
                        field_type = self._resolve_type(field_value)
                        description = field_value.get('description', '').replace('\n', ' ')
                        type_table.append(f"| {field_name} | {field_type} |{description} |")
                
            sections.append('\n'.join(type_table))
        
        return '\n\n'.join(sections)


def main():
    parser = argparse.ArgumentParser(
        prog='mdb-docgen',
        description='MDB 结构文档生成工具'
    )
    parser.add_argument('-t', '--type',
                        required=True,
                        choices=['dev', 'kepler'],
                        help='接口类型：dev-设备接口，kepler-资源接口')
    parser.add_argument('-p', '--path',
                        default=DEFAULT_TEMP_PATH,
                        help=F'MDB仓库路径（默认：{DEFAULT_TEMP_PATH})')
    parser.add_argument('-o', '--output',
                        default='./docs',
                        help='输出目录（默认，/docs）')

    args = parser.parse_args()

    generator = MDBMarkdownGenerator(
        mdb_root=args.path,
        interface_type=args.type,
    )

    try:
        generator.generate(output_dir=args.output)
    except Exception as e:
        logging.fatal(f"生成文档时发生错误：{str(e)}")
        exit(1)


if __name__ == '__main__':
    main()