import importlib.util
import sys
from pathlib import Path
from typing import Optional
import polars as pl

from .models import infer_pydantic_model, df_to_pydantic  # adjust imports as needed


def bootstrap_app(
    app_path: str,
    models_path: Optional[str] = None,
    dry_run: bool = False,
):
    """
    Import the FastAPI app, call endpoints with example input,
    infer models from their polars.DataFrame responses,
    write models.py, and patch the routes with response_model.

    Parameters
    ----------
    app_path : str
        Path to the FastAPI app Python file.
    models_path : Optional[str]
        Path to output models.py file.
    dry_run : bool
        If True, only preview changes without writing files.
    """
    # 1. Dynamically import app module
    spec = importlib.util.spec_from_file_location("app_module", app_path)
    app_module = importlib.util.module_from_spec(spec)
    sys.modules["app_module"] = app_module
    spec.loader.exec_module(app_module)

    app = getattr(app_module, "app", None)
    if app is None:
        raise RuntimeError("No FastAPI app instance named `app` found.")

    # 2. Find endpoints decorated for inference (implement your decorator tracking logic here)
    # For demonstration, assume a global registry `__inference_registry__`
    registry = getattr(app_module, "__inference_registry__", [])

    if not registry:
        print("No endpoints registered for model inference.")
        return

    models_code_lines = [
        "from pydantic import BaseModel\n\n",
        "# --- Articuno autogenerated models ---\n\n",
    ]

    for entry in registry:
        name = entry["name"]
        example_input = entry["example_input"]
        endpoint = entry["endpoint"]

        # Call endpoint with example input
        result = endpoint(**example_input)

        # Support both polars DataFrame and other types
        if isinstance(result, pl.DataFrame):
            model = infer_pydantic_model(result, model_name=name)
            # Generate code lines for this model (you can use codegen here for nicer output)
            from .codegen import generate_class_code

            code = generate_class_code(model, model_name=name)
            models_code_lines.append(code)
            models_code_lines.append("\n")

            # Patch route decorator to add response_model=...
            # Also remove decorator line for infer_response_model
            # You need to parse and rewrite app source file for that — implement as needed

    full_code = "".join(models_code_lines)

    if dry_run:
        print("=== DRY RUN: Generated models.py content ===")
        print(full_code)
    else:
        output_path = Path(models_path) if models_path else Path(app_path).parent / "models.py"
        output_path.write_text(full_code, encoding="utf-8")
        print(f"Wrote models to {output_path}")
