#!/usr/bin/env python3
"""
API 文档提取脚本
支持 FastAPI、TypeScript、Python 模块
"""

import subprocess
import sys
import json
from pathlib import Path
from typing import Dict, Any, Optional

# 项目配置
PROJECTS = {
    'backend': {
        'path': Path('D:/dongdiankaifa9/backend'),
        'type': 'fastapi',
        'entry': 'app.main:app',
        'output': 'api-docs/backend'
    },
    'frontend': {
        'path': Path('D:/dongdiankaifa9/frontend'),
        'type': 'typescript',
        'entries': ['lib', 'hooks', 'components'],
        'output': 'api-docs/frontend'
    },
    'hydro_generator_module': {
        'path': Path('D:/dongdiankaifa9/hydro_generator_module'),
        'type': 'python',
        'output': 'api-docs/hydro_generator'
    },
    'multiphysics_network': {
        'path': Path('D:/dongdiankaifa9/multiphysics_network'),
        'type': 'python',
        'output': 'api-docs/multiphysics'
    }
}


def extract_fastapi(name: str, config: Dict[str, Any], output_base: Path) -> bool:
    """提取 FastAPI OpenAPI 文档"""
    path = config['path']
    output_dir = output_base / config['output']
    output_dir.mkdir(parents=True, exist_ok=True)
    
    # 添加路径到 sys.path
    if str(path) not in sys.path:
        sys.path.insert(0, str(path))
    
    try:
        # 动态导入 app
        from app.main import app
        
        # 获取 OpenAPI schema
        openapi_schema = app.openapi()
        
        # 保存 JSON
        json_path = output_dir / 'openapi.json'
        with open(json_path, 'w', encoding='utf-8') as f:
            json.dump(openapi_schema, f, indent=2, ensure_ascii=False)
        
        # 生成 Markdown 摘要
        md_path = output_dir / 'API_SUMMARY.md'
        generate_api_markdown(openapi_schema, md_path)
        
        endpoints = len(openapi_schema.get('paths', {}))
        print(f"  ✓ Extracted {endpoints} endpoints → {output_dir}")
        return True
        
    except ImportError as e:
        print(f"  ✗ Import error: {e}")
        return False
    except Exception as e:
        print(f"  ✗ Error: {e}")
        return False


def generate_api_markdown(schema: Dict, output_path: Path):
    """从 OpenAPI schema 生成 Markdown"""
    lines = [
        f"# {schema.get('info', {}).get('title', 'API Reference')}",
        "",
        f"Version: {schema.get('info', {}).get('version', '1.0.0')}",
        "",
        "## Endpoints",
        "",
        "| Method | Path | Summary |",
        "|--------|------|---------|"
    ]
    
    for path, methods in schema.get('paths', {}).items():
        for method, details in methods.items():
            if method in ('get', 'post', 'put', 'delete', 'patch'):
                summary = details.get('summary', details.get('operationId', '-'))
                lines.append(f"| `{method.upper()}` | `{path}` | {summary} |")
    
    lines.extend([
        "",
        "## Schemas",
        ""
    ])
    
    for name, schema_def in schema.get('components', {}).get('schemas', {}).items():
        lines.append(f"### {name}")
        lines.append("")
        if 'properties' in schema_def:
            lines.append("| Property | Type | Required |")
            lines.append("|----------|------|----------|")
            required = schema_def.get('required', [])
            for prop, prop_def in schema_def['properties'].items():
                prop_type = prop_def.get('type', prop_def.get('$ref', 'any'))
                is_required = '✓' if prop in required else ''
                lines.append(f"| `{prop}` | {prop_type} | {is_required} |")
            lines.append("")
    
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write('\n'.join(lines))


def extract_typescript(name: str, config: Dict[str, Any], output_base: Path) -> bool:
    """提取 TypeScript 文档 (TypeDoc)"""
    path = config['path']
    output_dir = output_base / config['output']
    
    # 检查 TypeDoc 是否已安装
    try:
        result = subprocess.run(
            ['npx', 'typedoc', '--version'],
            cwd=path,
            capture_output=True,
            text=True
        )
        if result.returncode != 0:
            print(f"  ⚠ TypeDoc not installed, installing...")
            subprocess.run(
                ['npm', 'install', '--save-dev', 'typedoc', 'typedoc-plugin-markdown'],
                cwd=path,
                check=True
            )
    except FileNotFoundError:
        print(f"  ✗ npm/npx not found")
        return False
    
    # 运行 TypeDoc
    try:
        entries = config.get('entries', ['lib'])
        cmd = [
            'npx', 'typedoc',
            '--plugin', 'typedoc-plugin-markdown',
            '--out', str(output_dir),
            '--entryPointStrategy', 'expand',
            '--exclude', '**/node_modules/**',
            '--exclude', '**/*.test.*',
            '--readme', 'none'
        ]
        for entry in entries:
            entry_path = path / entry
            if entry_path.exists():
                cmd.extend(['--entryPoints', str(entry_path)])
        
        result = subprocess.run(cmd, cwd=path, capture_output=True, text=True)
        
        if result.returncode == 0:
            print(f"  ✓ TypeDoc generated → {output_dir}")
            return True
        else:
            print(f"  ✗ TypeDoc error: {result.stderr[:200]}")
            return False
            
    except Exception as e:
        print(f"  ✗ Error: {e}")
        return False


def extract_python_module(name: str, config: Dict[str, Any], output_base: Path) -> bool:
    """提取 Python 模块文档 (pdoc)"""
    path = config['path']
    output_dir = output_base / config['output']
    module_name = path.name
    
    # 检查 pdoc
    try:
        subprocess.run(['pdoc', '--version'], capture_output=True, check=True)
    except (FileNotFoundError, subprocess.CalledProcessError):
        print(f"  ⚠ pdoc not installed, installing...")
        subprocess.run([sys.executable, '-m', 'pip', 'install', 'pdoc'], check=True)
    
    # 运行 pdoc
    try:
        result = subprocess.run(
            [
                'pdoc', module_name,
                '--output-dir', str(output_dir),
                '--format', 'markdown'
            ],
            cwd=path.parent,
            capture_output=True,
            text=True
        )
        
        if result.returncode == 0:
            # 统计生成的文件
            md_files = list(output_dir.glob('**/*.md'))
            print(f"  ✓ pdoc generated {len(md_files)} files → {output_dir}")
            return True
        else:
            print(f"  ✗ pdoc error: {result.stderr[:200]}")
            return False
            
    except Exception as e:
        print(f"  ✗ Error: {e}")
        return False


EXTRACTORS = {
    'fastapi': extract_fastapi,
    'typescript': extract_typescript,
    'python': extract_python_module
}


def main(output_base: Optional[str] = None, projects: Optional[list] = None):
    """主入口"""
    base = Path(output_base) if output_base else Path.cwd()
    
    print("=" * 50)
    print("API Documentation Extraction")
    print("=" * 50)
    
    results = {}
    
    for name, config in PROJECTS.items():
        if projects and name not in projects:
            continue
            
        print(f"\n[{name}] ({config['type']})")
        
        if not config['path'].exists():
            print(f"  ✗ Path not found: {config['path']}")
            results[name] = False
            continue
        
        extractor = EXTRACTORS.get(config['type'])
        if extractor:
            results[name] = extractor(name, config, base)
        else:
            print(f"  ✗ Unknown type: {config['type']}")
            results[name] = False
    
    # 汇总
    print("\n" + "=" * 50)
    print("Summary")
    print("=" * 50)
    success = sum(1 for v in results.values() if v)
    print(f"Success: {success}/{len(results)}")
    
    return all(results.values())


if __name__ == '__main__':
    import argparse
    
    parser = argparse.ArgumentParser(description='Extract API documentation')
    parser.add_argument('--output', '-o', default='.', help='Output base directory')
    parser.add_argument('--projects', '-p', nargs='+', help='Specific projects to extract')
    
    args = parser.parse_args()
    
    success = main(args.output, args.projects)
    sys.exit(0 if success else 1)
