import uuid

from fastapi import APIRouter, Depends, status
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_db
from app.core.permissions import deny_vendor, require_permission
from app.core.security import AuthContext, get_auth_context
from app.crud.base import CRUDBase
from app.models.component import Component
from app.routers.pages import _check_html_block_permission
from app.schemas.component import ComponentCreate, ComponentKind, ComponentRead, ComponentUpdate
from app.schemas.navigation import PageBlockDef

router = APIRouter(prefix="/components", tags=["components"])
crud = CRUDBase[Component, ComponentCreate, ComponentUpdate](Component)

# Studio-only feature — a Public Portal (vendor) account never designs a
# Page or Form, so unlike masters/forms/pages/dashboard there's no
# per-item portal grant concept here; every route just denies vendor
# tokens outright rather than needing a require_portal_item() variant.


@router.get("", response_model=list[ComponentRead])
async def list_components(
    kind: ComponentKind | None = None,
    skip: int = 0,
    limit: int = 100,
    ctx: AuthContext = Depends(get_auth_context),
    db: AsyncSession = Depends(get_db),
    _: AuthContext = Depends(require_permission("components", "view")),
    __: AuthContext = Depends(deny_vendor()),
) -> list[Component]:
    return await crud.list(db, ctx.tenant_id, skip=skip, limit=limit, kind=kind)


@router.post("", response_model=ComponentRead, status_code=status.HTTP_201_CREATED)
async def create_component(
    payload: ComponentCreate,
    ctx: AuthContext = Depends(get_auth_context),
    db: AsyncSession = Depends(get_db),
    _: AuthContext = Depends(require_permission("components", "create")),
    __: AuthContext = Depends(deny_vendor()),
) -> Component:
    # Same "html" block gate a Page's own save/publish enforces (see
    # routers/pages.py::_check_html_block_permission) — a saved page_block
    # component containing one is just an html block waiting to be pasted
    # into a Page later, so it needs the same permission check up front.
    if payload.kind == "page_block":
        await _check_html_block_permission(db, ctx, [PageBlockDef.model_validate(payload.definition[0])])
    return await crud.create(db, ctx.tenant_id, payload, created_by=ctx.user_id)


@router.patch("/{component_id}", response_model=ComponentRead)
async def update_component(
    component_id: uuid.UUID,
    payload: ComponentUpdate,
    ctx: AuthContext = Depends(get_auth_context),
    db: AsyncSession = Depends(get_db),
    _: AuthContext = Depends(require_permission("components", "edit")),
    __: AuthContext = Depends(deny_vendor()),
) -> Component:
    return await crud.update(db, ctx.tenant_id, component_id, payload)


@router.delete("/{component_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_component(
    component_id: uuid.UUID,
    ctx: AuthContext = Depends(get_auth_context),
    db: AsyncSession = Depends(get_db),
    _: AuthContext = Depends(require_permission("components", "delete")),
    __: AuthContext = Depends(deny_vendor()),
) -> None:
    await crud.delete(db, ctx.tenant_id, component_id)
