#!/usr/bin/env python3
"""
C/H 文件到 Python 存根文件生成器

将 C 头文件 (.h) 或 C 源文件 (.c) 转换为 Python 存根文件 (.pyi)
生成的 Python 代码使用 TransPyC 语法，包含类型注解
"""
from __future__ import annotations

import os
import re
import sys
from typing import Any
from lib.core.VLogger import get_logger as _vlog


class CTypeMapper:

    # 硬编码 C 类型名 → Python 类型映射表
    # 这是 stub 生成器（C 头文件 → Python stub）专用的固定映射，
    # 不再依赖运行时 CTypeRegistry._cname_to_class（该映射已删除）。
    _CNAME_TO_PY: dict[str, str] = {
        # 基本类型
        'char': 't.CChar', 'int': 't.CInt', 'short': 't.CShort',
        'long': 't.CLong', 'long long': 't.CLongLong',
        'float': 't.CFloat', 'double': 't.CDouble', 'void': 't.CVoid',
        # unsigned / signed 变体
        'unsigned': 't.CUnsigned', 'unsigned char': 't.CUnsignedChar',
        'unsigned int': 't.CUnsignedInt', 'unsigned short': 't.CUnsignedShort',
        'unsigned long': 't.CUnsignedLong',
        'unsigned long long': 't.CUnsignedLongLong',
        'signed char': 't.CSignedChar',
        # bool / size_t
        'bool': 't.CBool', '_Bool': 't.CBool', 'size_t': 't.CSizeT',
        'ssize_t': 't.CLong',
        # stdint 固定宽度类型
        'int8_t': 't.CInt8T', 'int16_t': 't.CInt16T',
        'int32_t': 't.CInt32T', 'int64_t': 't.CInt64T',
        'uint8_t': 't.CUInt8T', 'uint16_t': 't.CUInt16T',
        'uint32_t': 't.CUInt32T', 'uint64_t': 't.CUInt64T',
        'intptr_t': 't.CIntPtrT', 'uintptr_t': 't.CUIntPtrT',
        'ptrdiff_t': 't.CPtrDiffT',
        # 宽字符 / 字符类型
        'wchar_t': 't.CWCharT', 'char8_t': 't.CChar8T',
        'char16_t': 't.CChar16T', 'char32_t': 't.CChar32T',
        # 浮点特化类型
        'float8_t': 't.CFloat8T', 'float16_t': 't.CFloat16T',
        'float32_t': 't.CFloat32T', 'float64_t': 't.CFloat64T',
        'float128_t': 't.CFloat128T',
        # signed 速记
        'signed': 't.CInt', 'signed int': 't.CInt',
        'signed short': 't.CShort', 'signed long': 't.CLong',
    }

    @classmethod
    def _ResolveCNameToPyType(cls, c_type: str) -> str:
        """将 C 类型名解析为 Python 类型字符串（如 'int' → 't.CInt'）

        使用硬编码映射表，不再依赖 CTypeRegistry._cname_to_class。
        未识别的类型原样返回（用于 struct/union/enum/typedef 用户自定义名）。
        """
        py: str | None = cls._CNAME_TO_PY.get(c_type)
        if py is not None:
            return py
        return c_type

    @classmethod
    def MapType(cls, c_type: str, IsPtr: bool = False, IsArray: bool = False) -> str:
        c_type = c_type.strip()

        IsConst: bool = 'const ' in c_type
        c_type = c_type.replace('const ', '').replace('const', '').strip()
        IsVolatile: bool = 'volatile ' in c_type
        c_type = c_type.replace('volatile ', '').replace('volatile', '').strip()
        IsStatic: bool = 'static ' in c_type
        c_type = c_type.replace('static ', '').replace('static', '').strip()
        IsExtern: bool = 'extern ' in c_type
        c_type = c_type.replace('extern ', '').replace('extern', '').strip()
        IsRegister: bool = 'register ' in c_type
        c_type = c_type.replace('register ', '').replace('register', '').strip()
        IsInline: bool = 'inline ' in c_type
        c_type = c_type.replace('inline ', '').replace('inline', '').strip()

        PtrSuffix: str = ''
        if IsPtr or c_type.endswith('*'):
            PtrSuffix = ' | t.CPtr'
            c_type = c_type.rstrip('*').strip()

        if c_type.startswith('struct '):
            c_type = c_type[7:].strip()
        elif c_type.startswith('union '):
            c_type = c_type[6:].strip()
        elif c_type.startswith('enum '):
            c_type = c_type[5:].strip()

        PyType: str = cls._ResolveCNameToPyType(c_type)

        result: str = PyType + PtrSuffix

        if IsArray:
            result += ' | t.CArrayPtr'

        return result


def _find_matching_brace(text: str, start: int) -> int:
    depth: int = 0
    i: int = start
    while i < len(text):
        if text[i] == '{':
            depth += 1
        elif text[i] == '}':
            depth -= 1
            if depth == 0:
                return i
        elif text[i] == '"' or text[i] == "'":
            quote: str = text[i]
            i += 1
            while i < len(text) and text[i] != quote:
                if text[i] == '\\':
                    i += 1
                i += 1
        elif text[i] == '/' and i + 1 < len(text) and text[i + 1] == '/':
            while i < len(text) and text[i] != '\n':
                i += 1
            continue
        elif text[i] == '/' and i + 1 < len(text) and text[i + 1] == '*':
            i += 2
            while i + 1 < len(text) and not (text[i] == '*' and text[i + 1] == '/'):
                i += 1
            i += 1
        i += 1
    return -1


def _strip_comments(content: str) -> str:
    result: list[str] = []
    i: int = 0
    while i < len(content):
        if content[i] == '/' and i + 1 < len(content) and content[i + 1] == '/':
            while i < len(content) and content[i] != '\n':
                i += 1
        elif content[i] == '/' and i + 1 < len(content) and content[i + 1] == '*':
            i += 2
            while i + 1 < len(content) and not (content[i] == '*' and content[i + 1] == '/'):
                i += 1
            i += 2
        elif content[i] == '"' or content[i] == "'":
            quote: str = content[i]
            result.append(content[i])
            i += 1
            while i < len(content) and content[i] != quote:
                if content[i] == '\\' and i + 1 < len(content):
                    result.append(content[i])
                    i += 1
                result.append(content[i])
                i += 1
            if i < len(content):
                result.append(content[i])
                i += 1
        else:
            result.append(content[i])
            i += 1
    return ''.join(result)


def _strip_preprocessor_guards(content: str) -> str:
    lines: list[str] = content.split('\n')
    filtered: list[str] = []
    for line in lines:
        stripped: str = line.strip()
        if stripped.startswith('#ifndef') and '_H' in stripped.upper():
            continue
        if stripped.startswith('#define') and '_H' in stripped.upper():
            continue
        if stripped == '#endif':
            continue
        filtered.append(line)
    return '\n'.join(filtered)


class CHeaderParser:
    """C 头文件解析器"""

    def __init__(self) -> None:
        self.defines: list[dict[str, str | None]] = []
        self.structs: dict[str, dict[str, Any]] = {}
        self.enums: dict[str, dict[str, Any]] = {}
        self.typedefs: list[dict[str, str]] = []
        self.functions: dict[str, dict[str, Any]] = {}
        self.variables: dict[str, dict[str, Any]] = {}
        self.unions: dict[str, dict[str, Any]] = {}
        self.func_ptr_typedefs: dict[str, dict[str, Any]] = {}
        self._typedef_struct_map: dict[str, str] = {}
        self._typedef_enum_map: dict[str, str] = {}
        self._typedef_union_map: dict[str, str] = {}

    def ParseFile(self, FilePath: str) -> None:
        with open(FilePath, 'r', encoding='utf-8') as f:
            content: str = f.read()
        self.ParseContent(content)

    def ParseContent(self, content: str) -> None:
        content = _strip_comments(content)
        content = _strip_preprocessor_guards(content)
        self._ParseDefines(content)
        self._ParseTypedefStructs(content)
        self._ParseTypedefEnums(content)
        self._ParseTypedefUnions(content)
        self._ParseFuncPtrTypedefs(content)
        self._ParseSimpleTypedefs(content)
        self._ParseStandaloneStructs(content)
        self._ParseStandaloneEnums(content)
        self._ParseStandaloneUnions(content)
        stripped: str = self._StripBodies(content)
        self._ParseFunctions(stripped)
        self._ParseVariables(stripped)

    def _StripBodies(self, content: str) -> str:
        result: str = content
        while True:
            pos: int = result.find('{')
            if pos < 0:
                break
            end: int = _find_matching_brace(result, pos)
            if end < 0:
                break
            result = result[:pos] + result[end + 1:]
        return result

    def _ParseDefines(self, content: str) -> None:
        for match in re.finditer(r'#define\s+(\w+)(?:\s+(.+?))?\s*$', content, re.MULTILINE):
            Name: str = match.group(1)
            Value: str | None = match.group(2)
            if Name.startswith('_') and Name.endswith('_'):
                continue
            if Name.startswith('__'):
                continue
            self.defines.append({
                'name': Name,
                'value': Value.strip() if Value else None,
            })

    def _ParseTypedefStructs(self, content: str) -> None:
        pattern: str = r'typedef\s+struct\s*(\w*)\s*\{'
        for match in re.finditer(pattern, content):
            brace_start: int = content.index('{', match.start())
            brace_end: int = _find_matching_brace(content, brace_start)
            if brace_end < 0:
                continue
            body: str = content[brace_start + 1:brace_end]
            rest: str = content[brace_end + 1:].lstrip()
            AliasMatch: re.Match[str] | None = re.match(r'(\w+)\s*;', rest)
            if not AliasMatch:
                continue
            AliasName: str = AliasMatch.group(1)
            TagName: str | None = match.group(1) if match.group(1) else None
            members: list[dict[str, Any]] = self._ParseStructMembers(body)
            self.structs[AliasName] = {
                'name': AliasName,
                'tag': TagName,
                'members': members,
            }
            if TagName:
                self._typedef_struct_map[TagName] = AliasName

    def _ParseTypedefEnums(self, content: str) -> None:
        pattern: str = r'typedef\s+enum\s*(\w*)\s*\{'
        for match in re.finditer(pattern, content):
            brace_start: int = content.index('{', match.start())
            brace_end: int = _find_matching_brace(content, brace_start)
            if brace_end < 0:
                continue
            body: str = content[brace_start + 1:brace_end]
            rest: str = content[brace_end + 1:].lstrip()
            AliasMatch: re.Match[str] | None = re.match(r'(\w+)\s*;', rest)
            if not AliasMatch:
                continue
            AliasName: str = AliasMatch.group(1)
            TagName: str | None = match.group(1) if match.group(1) else None
            values: list[dict[str, str | None]] = self._ParseEnumValues(body)
            self.enums[AliasName] = {
                'name': AliasName,
                'tag': TagName,
                'values': values,
            }
            if TagName:
                self._typedef_enum_map[TagName] = AliasName

    def _ParseTypedefUnions(self, content: str) -> None:
        pattern: str = r'typedef\s+union\s*(\w*)\s*\{'
        for match in re.finditer(pattern, content):
            brace_start: int = content.index('{', match.start())
            brace_end: int = _find_matching_brace(content, brace_start)
            if brace_end < 0:
                continue
            body: str = content[brace_start + 1:brace_end]
            rest: str = content[brace_end + 1:].lstrip()
            AliasMatch: re.Match[str] | None = re.match(r'(\w+)\s*;', rest)
            if not AliasMatch:
                continue
            AliasName: str = AliasMatch.group(1)
            TagName: str | None = match.group(1) if match.group(1) else None
            members: list[dict[str, Any]] = self._ParseStructMembers(body)
            self.unions[AliasName] = {
                'name': AliasName,
                'tag': TagName,
                'members': members,
            }
            if TagName:
                self._typedef_union_map[TagName] = AliasName

    def _ParseFuncPtrTypedefs(self, content: str) -> None:
        pattern: str = r'typedef\s+([\w\s\*]+?)\s*\(\s*\*\s*(\w+)\s*\)\s*\(([^)]*)\)\s*;'
        for match in re.finditer(pattern, content):
            ReturnType: str = match.group(1).strip()
            Name: str = match.group(2)
            ParamsStr: str = match.group(3).strip()
            params: list[dict[str, Any]] = self._ParseFuncParams(ParamsStr)
            self.func_ptr_typedefs[Name] = {
                'name': Name,
                'return_type': ReturnType,
                'params': params,
            }

    def _ParseSimpleTypedefs(self, content: str) -> None:
        stripped: str = self._StripBodies(content)
        pattern: str = r'typedef\s+([\w\s\*]+?)\s+(\w+)\s*;'
        for match in re.finditer(pattern, stripped):
            BaseType: str = match.group(1).strip()
            AliasName: str = match.group(2)
            if AliasName in self.structs:
                continue
            if AliasName in self.enums:
                continue
            if AliasName in self.unions:
                continue
            if AliasName in self.func_ptr_typedefs:
                continue
            if BaseType.startswith('typedef'):
                continue
            self.typedefs.append({'name': AliasName, 'base': BaseType})

    def _ParseStandaloneStructs(self, content: str) -> None:
        pattern: str = r'(?<!typedef\s)struct\s+(\w+)\s*\{'
        for match in re.finditer(pattern, content):
            TagName: str = match.group(1)
            if TagName in self._typedef_struct_map:
                continue
            if TagName in self.structs:
                continue
            brace_start: int = content.index('{', match.start())
            brace_end: int = _find_matching_brace(content, brace_start)
            if brace_end < 0:
                continue
            body: str = content[brace_start + 1:brace_end]
            members: list[dict[str, Any]] = self._ParseStructMembers(body)
            self.structs[TagName] = {
                'name': TagName,
                'tag': None,
                'members': members,
            }

    def _ParseStandaloneEnums(self, content: str) -> None:
        pattern: str = r'(?<!typedef\s)enum\s+(\w+)\s*\{'
        for match in re.finditer(pattern, content):
            TagName: str = match.group(1)
            if TagName in self._typedef_enum_map:
                continue
            if TagName in self.enums:
                continue
            brace_start: int = content.index('{', match.start())
            brace_end: int = _find_matching_brace(content, brace_start)
            if brace_end < 0:
                continue
            body: str = content[brace_start + 1:brace_end]
            values: list[dict[str, str | None]] = self._ParseEnumValues(body)
            self.enums[TagName] = {
                'name': TagName,
                'tag': None,
                'values': values,
            }

    def _ParseStandaloneUnions(self, content: str) -> None:
        pattern: str = r'(?<!typedef\s)union\s+(\w+)\s*\{'
        for match in re.finditer(pattern, content):
            TagName: str = match.group(1)
            if TagName in self._typedef_union_map:
                continue
            if TagName in self.unions:
                continue
            brace_start: int = content.index('{', match.start())
            brace_end: int = _find_matching_brace(content, brace_start)
            if brace_end < 0:
                continue
            body: str = content[brace_start + 1:brace_end]
            members: list[dict[str, Any]] = self._ParseStructMembers(body)
            self.unions[TagName] = {
                'name': TagName,
                'tag': None,
                'members': members,
            }

    def _ParseFunctions(self, content: str) -> None:
        pattern: str = r'(?:(?:static|extern|inline)\s+)*([\w][\w\s\*]*?)\b(\w+)\s*\(([^)]*)\)\s*;'
        for match in re.finditer(pattern, content):
            ReturnType: str = match.group(1).strip()
            FuncName: str = match.group(2)
            ParamsStr: str = match.group(3).strip()
            if FuncName in self.structs or FuncName in self.enums or FuncName in self.unions:
                continue
            if FuncName in self.func_ptr_typedefs:
                continue
            if FuncName in self.defines:
                continue
            if ReturnType in ('struct', 'union', 'enum', 'typedef'):
                continue
            if re.match(r'^\d', ReturnType):
                continue
            if not re.match(r'^[A-Za-z_]', FuncName):
                continue
            params: list[dict[str, Any]] = self._ParseFuncParams(ParamsStr)
            self.functions[FuncName] = {
                'name': FuncName,
                'return_type': ReturnType,
                'params': params,
            }

    def _ParseVariables(self, content: str) -> None:
        pattern: str = r'(?:(?:static|extern|volatile|const)\s+)*([\w][\w\s\*]*?)\s+(\w+)\s*(?:\[(\d*)\])?\s*;'
        for match in re.finditer(pattern, content):
            TypeStr: str = match.group(1).strip()
            VarName: str = match.group(2)
            ArraySize: str | None = match.group(3)
            if VarName in self.functions or VarName in self.structs or VarName in self.enums:
                continue
            if VarName in self.unions or VarName in self.func_ptr_typedefs:
                continue
            if VarName in self.defines:
                continue
            if TypeStr.startswith('typedef'):
                continue
            if TypeStr in ('struct', 'union', 'enum', 'typedef'):
                continue
            if re.match(r'^(if|else|while|for|return|switch|case|break|continue|do|goto)$', VarName):
                continue
            if not re.match(r'^[A-Za-z_]', VarName):
                continue
            IsPtr: bool = '*' in TypeStr
            IsArray: bool = ArraySize is not None
            self.variables[VarName] = {
                'name': VarName,
                'type': TypeStr,
                'IsPtr': IsPtr,
                'is_array': IsArray,
                'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None,
            }

    def _ParseStructMembers(self, body: str) -> list[dict[str, Any]]:
        members: list[dict[str, Any]] = []
        for line in body.split(';'):
            line = line.strip()
            if not line:
                continue
            arr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s+(\w+)\s*\[(\d*)\]', line)
            if arr_match:
                MemberType: str = arr_match.group(1).strip()
                MemberName: str = arr_match.group(2)
                ArraySize: str = arr_match.group(3)
                members.append({
                    'name': MemberName,
                    'type': MemberType,
                    'is_array': True,
                    'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None,
                })
                continue
            ptr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s*\*\s*(\w+)', line)
            if ptr_match:
                MemberType: str = ptr_match.group(1).strip() + ' *'
                MemberName: str = ptr_match.group(2)
                members.append({
                    'name': MemberName,
                    'type': MemberType,
                    'IsPtr': True,
                })
                continue
            simple_match: re.Match[str] | None = re.match(r'([\w\s]+?)\s+(\w+)', line)
            if simple_match:
                MemberType: str = simple_match.group(1).strip()
                MemberName: str = simple_match.group(2)
                members.append({
                    'name': MemberName,
                    'type': MemberType,
                })
        return members

    def _ParseEnumValues(self, body: str) -> list[dict[str, str | None]]:
        values: list[dict[str, str | None]] = []
        for item in body.split(','):
            item = item.strip()
            if not item:
                continue
            eq_pos: int = item.find('=')
            if eq_pos >= 0:
                Name: str = item[:eq_pos].strip()
                Value: str | None = item[eq_pos + 1:].strip()
            else:
                Name = item.strip()
                Value = None
            if Name and re.match(r'^[A-Za-z_]\w*$', Name):
                values.append({'name': Name, 'value': Value})
        return values

    def _ParseFuncParams(self, params_str: str) -> list[dict[str, Any]]:
        params: list[dict[str, Any]] = []
        if not params_str or params_str.strip() == 'void' or params_str.strip() == '':
            return params
        for param in params_str.split(','):
            param = param.strip()
            if not param:
                continue
            func_ptr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s*\(\s*\*\s*(\w*)\s*\)\s*\([^)]*\)', param)
            if func_ptr_match:
                RetType: str = func_ptr_match.group(1).strip()
                ParamName: str = func_ptr_match.group(2) or 'callback'
                params.append({
                    'name': ParamName,
                    'type': RetType + ' (*)',
                    'is_func_ptr': True,
                })
                continue
            arr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s+(\w+)\s*\[\d*\]', param)
            if arr_match:
                ParamType: str = arr_match.group(1).strip()
                ParamName: str = arr_match.group(2)
                params.append({
                    'name': ParamName,
                    'type': ParamType,
                    'is_array': True,
                })
                continue
            tokens: list[str] = param.split()
            if len(tokens) >= 2:
                LastToken: str = tokens[-1]
                PtrCount: int = 0
                while LastToken.startswith('*'):
                    PtrCount += 1
                    LastToken = LastToken[1:]
                TypeTokens: list[str] = tokens[:-1]
                for _ in range(PtrCount):
                    TypeTokens.append('*')
                ParamName: str = LastToken
                ParamType: str = ' '.join(TypeTokens)
                if not ParamName:
                    ParamName = 'arg'
                    ParamType = param
                params.append({
                    'name': ParamName,
                    'type': ParamType,
                })
            elif len(tokens) == 1:
                params.append({
                    'name': 'arg',
                    'type': tokens[0],
                })
        return params


class PythonStubGenerator:
    """Python 存根文件生成器"""

    def __init__(self, parser: CHeaderParser) -> None:
        self.parser: CHeaderParser = parser
        self.OutputLines: list[str] = []

    def generate(self, ModuleName: str | None = None) -> str:
        self.OutputLines = []
        self._AddHeader(ModuleName)
        self._GenerateImports()
        self._GenerateDefines()
        self._GenerateFuncPtrTypedefs()
        self._GenerateSimpleTypedefs()
        self._GenerateStructs()
        self._GenerateUnions()
        self._GenerateEnums()
        self._GenerateVariables()
        self._GenerateFunctions()
        return '\n'.join(self.OutputLines)

    def _AddHeader(self, ModuleName: str | None = None) -> None:
        self.OutputLines.append('"""')
        self.OutputLines.append('Auto-generated Python stub file from C header')
        if ModuleName:
            self.OutputLines.append(f'Module: {ModuleName}')
        self.OutputLines.append('"""')
        self.OutputLines.append('')

    def _GenerateImports(self) -> None:
        self.OutputLines.append('import t')
        self.OutputLines.append('import c')
        self.OutputLines.append('')

    def _GenerateDefines(self) -> None:
        if not self.parser.defines:
            return
        for define in self.parser.defines:
            Name: str = define['name']
            Value: str | None = define['value']
            if Value is not None:
                self.OutputLines.append(f'{Name}: t.CDefine = {Value}')
            else:
                self.OutputLines.append(f'{Name}: t.CDefine')
        self.OutputLines.append('')

    def _GenerateFuncPtrTypedefs(self) -> None:
        if not self.parser.func_ptr_typedefs:
            return
        for Name, Info in self.parser.func_ptr_typedefs.items():
            RetType: str = CTypeMapper.MapType(Info['return_type'])
            ParamTypes: list[str] = []
            for p in Info['params']:
                ParamTypes.append(CTypeMapper.MapType(p['type']))
            ParamStr: str = ', '.join(ParamTypes) if ParamTypes else ''
            self.OutputLines.append(f'{Name}: t.CTypedef = t.Callable[[{ParamStr}], {RetType}]')
        self.OutputLines.append('')

    def _GenerateSimpleTypedefs(self) -> None:
        if not self.parser.typedefs:
            return
        for td in self.parser.typedefs:
            AliasName: str = td['name']
            BaseType: str = td['base']
            PyType: str = CTypeMapper.MapType(BaseType)
            self.OutputLines.append(f'{AliasName}: t.CTypedef | {PyType}')
        self.OutputLines.append('')

    def _GenerateStructs(self) -> None:
        if not self.parser.structs:
            return
        for StructName, StructInfo in self.parser.structs.items():
            self.OutputLines.append(f'@c.Attribute(t.attr.packed)')
            self.OutputLines.append(f'class {StructName}(t.CStruct):')
            if StructInfo['members']:
                for member in StructInfo['members']:
                    MemberName: str = member['name']
                    IsPtr: bool = member.get('IsPtr', False)
                    IsArray: bool = member.get('is_array', False)
                    ArraySize: int | None = member.get('array_size')
                    PyType: str = CTypeMapper.MapType(member['type'], IsPtr=IsPtr)
                    if IsArray and ArraySize is not None:
                        self.OutputLines.append(f'    {MemberName}: list[{PyType}, {ArraySize}]')
                    elif IsArray:
                        self.OutputLines.append(f'    {MemberName}: {PyType} | t.CArrayPtr')
                    else:
                        self.OutputLines.append(f'    {MemberName}: {PyType}')
            else:
                self.OutputLines.append('    pass')
            self.OutputLines.append('')

    def _GenerateUnions(self) -> None:
        if not self.parser.unions:
            return
        for UnionName, UnionInfo in self.parser.unions.items():
            self.OutputLines.append(f'@c.Attribute(t.attr.packed)')
            self.OutputLines.append(f'class {UnionName}(t.CUnion):')
            if UnionInfo['members']:
                for member in UnionInfo['members']:
                    PyType: str = CTypeMapper.MapType(member['type'], IsPtr=member.get('IsPtr', False))
                    self.OutputLines.append(f'    {member["name"]}: {PyType}')
            else:
                self.OutputLines.append('    pass')
            self.OutputLines.append('')

    def _GenerateEnums(self) -> None:
        if not self.parser.enums:
            return
        for EnumName, EnumInfo in self.parser.enums.items():
            self.OutputLines.append(f'class __{EnumName.lower()}(t.CEnum):')
            if EnumInfo['values']:
                for value in EnumInfo['values']:
                    if value['value'] is not None:
                        self.OutputLines.append(f'    {value["name"]}: t.CDefine = {value["value"]}')
                    else:
                        self.OutputLines.append(f'    {value["name"]}: t.CDefine')
            else:
                self.OutputLines.append('    pass')
            self.OutputLines.append(f'{EnumName}: t.CTypedef = __{EnumName.lower()}')
            self.OutputLines.append('')

    def _GenerateVariables(self) -> None:
        if not self.parser.variables:
            return
        for VarName, VarInfo in self.parser.variables.items():
            PyType: str = CTypeMapper.MapType(VarInfo['type'], IsPtr=VarInfo['IsPtr'], IsArray=VarInfo['is_array'])
            self.OutputLines.append(f'{VarName}: {PyType}')
        self.OutputLines.append('')

    def _GenerateFunctions(self) -> None:
        if not self.parser.functions:
            return
        for FuncName, FuncInfo in self.parser.functions.items():
            params: list[str] = []
            for param in FuncInfo['params']:
                if param.get('is_func_ptr'):
                    PyType: str = CTypeMapper.MapType(param['type'])
                elif param.get('is_array'):
                    PyType: str = CTypeMapper.MapType(param['type'], IsPtr=True)
                else:
                    PyType: str = CTypeMapper.MapType(param['type'])
                params.append(f'{param["name"]}: {PyType}')
            ParamStr: str = ', '.join(params) if params else ''
            ReturnType: str = CTypeMapper.MapType(FuncInfo['return_type'])
            self.OutputLines.append(f'def {FuncName}({ParamStr}) -> {ReturnType}: pass')
        self.OutputLines.append('')


def GenerateStubFromC(InputFile: str, OutputFile: str | None = None) -> str:
    parser: CHeaderParser = CHeaderParser()
    parser.ParseFile(InputFile)
    generator: PythonStubGenerator = PythonStubGenerator(parser)
    ModuleName: str = os.path.splitext(os.path.basename(InputFile))[0]
    content: str = generator.generate(ModuleName)
    if OutputFile:
        with open(OutputFile, 'w', encoding='utf-8') as f:
            f.write(content)
        _vlog().success(f"生成: {OutputFile}")
    return content


if __name__ == '__main__':
    if len(sys.argv) >= 3:
        GenerateStubFromC(sys.argv[1], sys.argv[2])
    elif len(sys.argv) == 2:
        _vlog().info(GenerateStubFromC(sys.argv[1]))
    else:
        test_code: str = '''
struct memory_block {
    uint64_t size;
    uint8_t state;
    uint8_t order;
    struct memory_block *next;
    struct memory_block *prev;
};

typedef struct memory_block memory_block_t;

enum color_format {
    COLOR_FORMAT_BGRA,
    COLOR_FORMAT_RGBA,
    COLOR_FORMAT_BGR,
    COLOR_FORMAT_RGB
};

void *malloc(size_t size);
void free(void *ptr);
void *memcpy(void *dest, const void *src, size_t n);
'''
        parser: CHeaderParser = CHeaderParser()
        parser.ParseContent(test_code)
        generator: PythonStubGenerator = PythonStubGenerator(parser)
        _vlog().info(generator.generate("test_header"))
