<%~ includeFile('../header.eta', it) %>

from typing import List, Optional, Union
from fastapi import APIRouter, Depends, Header, HTTPException, Query, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_db
from ..models.<%= it.entityName.toLowerCase() %> import <%= it.entityName -%>

from ..schemas.<%= it.entityName.toLowerCase() %> import (
    <%= it.entityName %> as <%= it.entityName %>Schema,
    <%= it.entityName %>Create,
    <%= it.entityName %>Update,
    <%= it.entityName %>List,
)
from ..services.<%= it.entityName.toLowerCase() %> import <%= it.entityName %>Service
from ..utils.query import parse_query_params, QueryParseError

router = APIRouter(
    prefix="/<%= it.pluralEntityName.toLowerCase() %>",
    tags=["<%= it.pluralEntityName %>"],
)


@router.get(
    "",
    summary="Retrieve multiple <%= it.pluralEntityName %>",
    response_model=Union[<%= it.entityName %>List, List[<%= it.entityName %>Schema]],
)
async def get_many(
    request: Request,
    db: AsyncSession = Depends(get_db),
    x_crud_dialect: Optional[str] = Header(default=None, alias="X-Crud-Dialect"),
):
    """
    Retrieve <%= it.pluralEntityName %> under either query dialect.

    Dialect is chosen by the `X-Crud-Dialect` header (postgrest|nestjsx), else
    inferred from the param shape (parity with the TypeScript services).

    nestjsx (default) — envelope response {data,count,total,page,pageCount}:
    - filter=field||$operator||value (repeatable)
    - or=field||$operator||value (repeatable)
    - sort=field,ASC (repeatable)
    - fields=field1,field2
    - join=relation (repeatable)
    - limit=25&page=1

    postgrest — bare JSON array response:
    - select=col,alias:col,rel(cols)
    - col=op.value filters (eq/neq/gt/gte/lt/lte/like/ilike/in/is, not.<op>)
    - or=(...) / and=(...) logical groups
    - order=col.asc|desc[.nullsfirst|nullslast]
    - limit=..&offset=.. (windows the bare array)
    """
    service = <%= it.entityName %>Service(db)
    try:
        options = parse_query_params(request.query_params, x_crud_dialect)
    except QueryParseError as exc:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(exc),
        )

    if options.dialect == "postgrest":
        # PostgREST always returns a bare JSON array (never the envelope), even
        # when limit/offset are present.
        try:
            rows = await service.get_many_list(options)
        except QueryParseError as exc:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=str(exc),
            )
        payload = [
            r if isinstance(r, dict) else <%= it.entityName %>Schema.model_validate(r)
            for r in rows
        ]
        return JSONResponse(content=jsonable_encoder(payload))

    try:
        result = await service.get_many(options)
    except QueryParseError as exc:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(exc),
        )

    return <%= it.entityName %>List(
        data=result.data,
        count=result.count,
        total=result.total,
        page=result.page,
        pageCount=result.page_count,
    )


@router.get(
    "/{id}",
    response_model=<%= it.entityName %>Schema,
    summary="Retrieve a single <%= it.entityName %>",
)
async def get_one(
    id: <% if (it.primaryKeyType === 'uuid') { %>str<% } else { %>int<% } %>,
    request: Request,
    db: AsyncSession = Depends(get_db),
) -> <%= it.entityName %>Schema:
    """
    Retrieve a single <%= it.entityName %> by ID.

    Supports query parameters:
    - join=relation (repeatable)
    """
    service = <%= it.entityName %>Service(db)

    options = parse_query_params(request.query_params)
    joins = [j.relation for j in options.joins] if options.joins else None

    item = await service.get_one(id, joins=joins)
    if not item:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"<%= it.entityName %> with id {id} not found",
        )
    return item


@router.post(
    "",
    response_model=<%= it.entityName %>Schema,
    status_code=status.HTTP_201_CREATED,
    summary="Create a single <%= it.entityName %>",
)
async def create_one(
    data: <%= it.entityName %>Create,
    db: AsyncSession = Depends(get_db),
) -> <%= it.entityName %>Schema:
    """
    Create a new <%= it.entityName %>.
    """
    service = <%= it.entityName %>Service(db)
    return await service.create_one(data)


@router.post(
    "/bulk",
    response_model=List[<%= it.entityName %>Schema],
    status_code=status.HTTP_201_CREATED,
    summary="Create multiple <%= it.pluralEntityName %>",
)
async def create_many(
    data: List[<%= it.entityName %>Create],
    db: AsyncSession = Depends(get_db),
) -> List[<%= it.entityName %>Schema]:
    """
    Create multiple <%= it.pluralEntityName %>.
    """
    service = <%= it.entityName %>Service(db)
    return await service.create_many(data)


@router.patch(
    "/{id}",
    response_model=<%= it.entityName %>Schema,
    summary="Update a single <%= it.entityName %>",
)
async def update_one(
    id: <% if (it.primaryKeyType === 'uuid') { %>str<% } else { %>int<% } %>,
    data: <%= it.entityName %>Update,
    db: AsyncSession = Depends(get_db),
) -> <%= it.entityName %>Schema:
    """
    Update an existing <%= it.entityName %>.
    """
    service = <%= it.entityName %>Service(db)
    item = await service.update_one(id, data)
    if not item:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"<%= it.entityName %> with id {id} not found",
        )
    return item


@router.put(
    "/{id}",
    response_model=<%= it.entityName %>Schema,
    summary="Replace a single <%= it.entityName %>",
)
async def replace_one(
    id: <% if (it.primaryKeyType === 'uuid') { %>str<% } else { %>int<% } %>,
    data: <%= it.entityName %>Create,
    db: AsyncSession = Depends(get_db),
) -> <%= it.entityName %>Schema:
    """
    Replace an existing <%= it.entityName %>.
    """
    service = <%= it.entityName %>Service(db)
    item = await service.replace_one(id, data)
    if not item:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"<%= it.entityName %> with id {id} not found",
        )
    return item


@router.delete(
    "/{id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Delete a single <%= it.entityName %>",
)
async def delete_one(
    id: <% if (it.primaryKeyType === 'uuid') { %>str<% } else { %>int<% } %>,
    db: AsyncSession = Depends(get_db),
) -> None:
    """
    Delete a <%= it.entityName %> by ID.
    """
    service = <%= it.entityName %>Service(db)
    deleted = await service.delete_one(id)
    if not deleted:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"<%= it.entityName %> with id {id} not found",
        )
