"""
API routes for documentation generation.

Provides endpoints to generate human-readable documentation
from data contracts.
"""

from __future__ import annotations

from typing import Any

from fastapi import APIRouter, Depends, HTTPException, Query, Request

from pycharter.api.dependencies.store import get_metadata_store
from pycharter.api.models.docs import (
    DocsFormat,
    DocsRequest,
    DocsResponse,
    DocsSectionRequest,
    DocsSectionResponse,
)
from pycharter.contract_parser import parse_contract
from pycharter.docs_generator import DocsGenerator, generate_docs
from pycharter.docs_generator.renderers import HTMLRenderer, MarkdownRenderer
from pycharter.metadata_store import MetadataStoreClient

router = APIRouter(prefix="/docs", tags=["Documentation"])


@router.get(
    "/playground-routes",
    summary="List REST API routes for playground",
    description="Return a list of REST API routes (path, method, summary, tag) derived from the OpenAPI schema for use in the API Playground UI.",
    tags=["Documentation"],
)
async def get_playground_routes(request: Request) -> dict[str, Any]:
    """
    Return routes suitable for the API Playground.

    Reads the OpenAPI schema from the running app and returns a minimal list
    of path, method, summary, and tag so the UI can build the playground
    without maintaining a duplicate list.
    """
    try:
        openapi = request.app.openapi()
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Failed to generate OpenAPI schema: {e}",
        ) from e

    paths = openapi.get("paths") or {}
    routes: list[dict[str, Any]] = []

    for path, path_item in paths.items():
        if not isinstance(path_item, dict):
            continue
        if not path.startswith("/api/v1"):
            continue
        for method in ("get", "post", "put", "patch", "delete"):
            op = path_item.get(method)
            if not isinstance(op, dict):
                continue
            summary = op.get("summary") or op.get("description") or ""
            tags = op.get("tags") or []
            tag = tags[0] if tags else ""
            routes.append(
                {
                    "path": path,
                    "method": method.upper(),
                    "summary": summary[:200] if summary else "",
                    "tag": tag,
                }
            )

    return {"routes": routes}


@router.post(
    "/generate",
    response_model=DocsResponse,
    summary="Generate documentation from contract",
    description="Generate human-readable documentation from contract data",
    tags=["Documentation"],
)
async def generate_documentation(request: DocsRequest) -> DocsResponse:
    """
    Generate documentation from a contract.

    Accepts contract data and generates formatted documentation
    in the specified format (Markdown or HTML).
    """
    try:
        # Parse the contract
        contract = parse_contract(request.contract, validate=False)

        # Generate documentation
        docs = generate_docs(
            contract,
            format=request.format.value,
            include_schema=request.include_schema,
            include_coercions=request.include_coercions,
            include_validations=request.include_validations,
            include_metadata=request.include_metadata,
        )

        # Extract schema name and version
        schema_name = contract.schema.get("title") or contract.metadata.get("title")
        version = contract.versions.get("schema") or contract.schema.get("version")

        return DocsResponse(
            documentation=docs,
            format=request.format,
            schema_name=schema_name,
            version=version,
        )

    except Exception as e:
        raise HTTPException(
            status_code=400, detail=f"Failed to generate documentation: {e}"
        )


@router.post(
    "/section",
    response_model=DocsSectionResponse,
    summary="Generate a specific documentation section",
    description="Generate a specific section of documentation from contract data",
    tags=["Documentation"],
)
async def generate_section(request: DocsSectionRequest) -> DocsSectionResponse:
    """
    Generate a specific section of documentation.

    Sections: 'schema', 'coercions', 'validations', 'metadata'
    """
    try:
        # Parse the contract
        contract = parse_contract(request.contract, validate=False)

        # Select renderer
        if request.format == DocsFormat.HTML:
            renderer = HTMLRenderer()
        else:
            renderer = MarkdownRenderer()

        generator = DocsGenerator(renderer=renderer)

        # Generate the requested section
        section = request.section.lower()
        if section == "schema":
            content = generator.generate_schema_section(contract.schema)
        elif section in ("coercions", "coercion_rules"):
            content = generator.generate_coercion_section(contract.coercion_rules)
        elif section in ("validations", "validation_rules"):
            content = generator.generate_validation_section(contract.validation_rules)
        elif section == "metadata":
            content = generator.generate_metadata_section(contract)
        else:
            raise HTTPException(
                status_code=400,
                detail=f"Unknown section: {section}. Valid sections: schema, coercions, validations, metadata",
            )

        return DocsSectionResponse(
            section=section,
            content=content,
            format=request.format,
        )

    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=400, detail=f"Failed to generate section: {e}")


@router.get(
    "/{contract_name}/{contract_version}",
    response_model=DocsResponse,
    summary="Generate documentation for a stored contract",
    description="Generate documentation for a data contract by name and version",
    tags=["Documentation"],
)
async def get_schema_docs(
    contract_name: str,
    contract_version: str,
    format: DocsFormat = Query(
        default=DocsFormat.MARKDOWN, description="Output format"
    ),
    store: MetadataStoreClient = Depends(get_metadata_store),
) -> DocsResponse:
    """Generate documentation for a data contract from the metadata store."""
    try:
        schema_data = store.get_complete_schema(contract_name, contract_version)
        if not schema_data:
            raise HTTPException(
                status_code=404,
                detail=f"Contract not found: {contract_name!r} @ {contract_version!r}",
            )
        contract_data = {"schema": schema_data}
        try:
            r = store.get_coercion_rules(contract_name, contract_version)
            if r:
                contract_data["coercion_rules"] = r
        except Exception:
            pass
        try:
            r = store.get_validation_rules(contract_name, contract_version)
            if r:
                contract_data["validation_rules"] = r
        except Exception:
            pass
        try:
            r = store.get_metadata(contract_name, contract_version)
            if r:
                contract_data["metadata"] = r
        except Exception:
            pass
        contract = parse_contract(contract_data, validate=False)
        docs = generate_docs(contract, format=format.value)
        return DocsResponse(
            documentation=docs,
            format=format,
            schema_name=contract_name,
            version=contract_version,
        )

    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=500, detail=f"Failed to generate documentation: {e}"
        )
