import argparse
import os
import json
import subprocess
import sys
import logging
from typing import Optional, List, Dict, Any

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def parse_arguments() -> argparse.Namespace:
    """Parse command line arguments."""
    parser = argparse.ArgumentParser(description='Generate OpenAPI/Swagger documentation from FastAPI or Flask apps.')
    parser.add_argument('app_file', type=str, help='Path to the Python file containing the app (e.g., app.py)')
    parser.add_argument('--output', type=str, default='docs/index.html', help='Output HTML file path (default: docs/index.html)')
    parser.add_argument('--port', type=int, default=8000, help='Port number for the documentation server (default: 8000)')
    parser.add_argument('--framework', type=str, choices=['fastapi', 'flask'], default='fastapi',
                        help='Framework used (default: fastapi)')
    parser.add_argument('--help', action='help', help='Show this help message and exit')
    return parser.parse_args()

def generate_swagger_json(app_file: str, framework: str) -> Optional[Dict[str, Any]]:
    """
    Generate the OpenAPI/Swagger JSON from the app.
    
    Args:
        app_file: Path to the app file
        framework: 'fastapi' or 'flask'
        
    Returns:
        OpenAPI JSON data or None if failed
    """
    try:
        if framework == 'fastapi':
            # For FastAPI, we can extract the docs using the app's openapi() method
            # We need to import the app and call openapi()
            # This requires the app to be in the same directory or properly imported
            # We'll use subprocess to run a separate script to extract the JSON
            script = f"""
import sys
import os
import json
from importlib import import_module

app_file = '{app_file}'
os.chdir(os.path.dirname(app_file))
module_name = os.path.splitext(os.path.basename(app_file))[0]
try:
    app_module = import_module(module_name)
    app = getattr(app_module, 'app', None)
    if app and hasattr(app, 'openapi'):
        print(json.dumps(app.openapi()))
    else:
        print(json.dumps({{}}))
except Exception as e:
    print(json.dumps({{}}))
    print(f"Error: {{e}}", file=sys.stderr)
            """
            result = subprocess.run(
                [sys.executable, '-c', script],
                capture_output=True,
                text=True,
                check=False
            )
            if result.returncode != 0:
                logging.error("Failed to generate OpenAPI JSON: %s", result.stderr)
                return None
            try:
                return json.loads(result.stdout)
            except json.JSONDecodeError:
                logging.error("Failed to decode JSON: %s", result.stdout)
                return None
        elif framework == 'flask':
            # For Flask, we can use the swagger extension
            # This is more complex and requires the app to have the swagger extension
            # For simplicity, we'll assume that the app has a swagger.json endpoint
            # This is not a general solution but a placeholder
            logging.warning("Flask framework support is limited. Use FastAPI for better results.")
            return {}
        else:
            logging.error(f"Unsupported framework: {framework}")
            return None
    except Exception as e:
        logging.error("Error generating OpenAPI JSON: %s", e)
        return None

def generate_html_from_json(json_data: Dict[str, Any], output_file: str) -> None:
    """
    Generate HTML documentation from OpenAPI JSON using Swagger UI.
    
    Args:
        json_data: OpenAPI JSON data
        output_file: Path to the output HTML file
    """
    try:
        # Create the directory if it doesn't exist
        os.makedirs(os.path.dirname(output_file), exist_ok=True)
        
        # Write the JSON file
        json_path = os.path.join(os.path.dirname(output_file), "swagger.json")
        with open(json_path, "w") as f:
            json.dump(json_data, f, indent=2)

        # Generate HTML using Swagger UI
        html_content = f"""
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>API Documentation</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css" />
  <style>
    html {{
      box-sizing: border-box;
      overflow: -moz-scrollbars-none;
      overflow-y: scroll;
    }}
    *, *:before, *:after {{
      box-sizing: inherit;
    }}
    body {{
      margin: 0;
      background: #fafafa;
    }}
  </style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = () => {{
  window.ui = SwaggerUIBundle({{
    url: '{json_path}',
    dom_id: '#swagger-ui',
    presets: [
      SwaggerUIBundle.presets.apis,
      SwaggerUIStandalonePreset
    ],
    layout: "StandaloneLayout"
  }})
}}
</script>
</body>
</html>
"""
        with open(output_file, "w") as f:
            f.write(html_content)
        logging.info(f"Generated HTML documentation at: {output_file}")
    except Exception as e:
        logging.error("Error generating HTML: %s", e)


def main():
    args = parse_arguments()
    json_data = generate_swagger_json(args.app_file, args.framework)
    if json_data:
        generate_html_from_json(json_data, args.output)

if __name__ == "__main__":
    main()