from nikame.codegen.base import BaseCodegen, CodegenContext, WiringInfo
from nikame.config.schema import NikameConfig
from nikame.codegen.ai_synthesizer import AISynthesizer
from nikame.utils.logger import console
import json


class GraphQLCodegen(BaseCodegen):
    NAME = "graphql"
    DESCRIPTION = "GraphQL API (Strawberry) auto-generated from schema"

    STRAWBERRY_TYPE_MAP = {
        "str": "str",
        "int": "int",
        "float": "float",
        "bool": "bool",
        "datetime": "datetime",
        "uuid": "uuid.UUID",
        "email": "str",
        "text": "str",
        "json": "str", # Strawberry JSON scalars need custom handling normally
    }

    def __init__(self, ctx: CodegenContext, config: NikameConfig) -> None:
        super().__init__(ctx, config)
        self.config = config
        self.ai = AISynthesizer()

    def generate(self) -> list[tuple[str, str]]:
        if not self.config.models:
            console.print("[warning]No models defined for GraphQL generation.[/warning]")
            return []

        console.print("[info]Synthesizing dynamic Strawberry GraphQL schema...[/info]")
        
        models_summary = {}
        for name, model_cfg in self.config.models.items():
            models_summary[name] = model_cfg.model_dump().get("fields", {})
            
        context_str = json.dumps(models_summary, indent=2)
        biz_context = self.config.description or "A backend application."

        prompt_types = (
            "You are an expert in Python and Strawberry GraphQL. "
            f"Given these domain models:\n{context_str}\n"
            "Generate Strawberry Types and input types for each model. "
            "Output ONLY the raw Python code (no markdown). Do not include Strawberry query/mutation classes here."
        )
        types_code = self.ai.synthesize_code(prompt_types, biz_context)
        
        prompt_schema = (
            "You are an expert in Python and Strawberry GraphQL. "
            f"Given these domain models:\n{context_str}\n"
            "Assume Strawberry types exist in `app.graphql.types`. "
            "Write the Strawberry Query and Mutation classes, and initialize `schema = strawberry.Schema(...)`. "
            "Include basic CRUD resolvers. Output ONLY raw Python code."
        )
        schema_code = self.ai.synthesize_code(prompt_schema, biz_context)
        
        prompt_router = (
            "You are an expert in FastAPI and Strawberry. "
            "Assume a Strawberry schema exists at `app.graphql.schema.schema`. "
            "Write a FastAPI router object named `router = APIRouter(...)` that mounts the Strawberry "
            "GraphQLRouter on `/`. Output ONLY raw Python code."
        )
        router_code = self.ai.synthesize_code(prompt_router, biz_context)

        return [
            ("app/graphql/types.py", types_code),
            ("app/graphql/schema.py", schema_code),
            ("app/api/v1/endpoints/graphql.py", router_code),
        ]

    def wiring(self) -> WiringInfo:
        return WiringInfo(
            imports=["from app.api.v1.endpoints.graphql import router as graphql_router"],
            routers=["app.include_router(graphql_router, prefix=\"/graphql\")"],
            requirements=["strawberry-graphql[fastapi]>=0.219.0"]
        )
