"""
Site management API endpoints.

Routes: /api/tenants/{tenant_id}/sites

RBAC:
- viewer: GET (read-only)
- operator: POST, PUT, device assignment (write)
- tenant_admin/admin: DELETE
"""

import uuid

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

from app.database import get_db
from app.middleware.rbac import require_operator_or_above, require_tenant_admin_or_above
from app.middleware.tenant_context import CurrentUser, get_current_user
from app.routers.devices import _check_tenant_access
from app.schemas.site import SiteCreate, SiteListResponse, SiteResponse, SiteUpdate
from app.services import site_service

router = APIRouter(tags=["sites"])


class BulkAssignRequest(BaseModel):
    """Request body for bulk device assignment."""

    device_ids: list[uuid.UUID]


# ---------------------------------------------------------------------------
# CRUD
# ---------------------------------------------------------------------------


@router.get(
    "/tenants/{tenant_id}/sites",
    response_model=SiteListResponse,
    summary="List sites",
)
async def list_sites(
    tenant_id: uuid.UUID,
    current_user: CurrentUser = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> SiteListResponse:
    """List all sites for a tenant with health rollup. Viewer role and above."""
    await _check_tenant_access(current_user, tenant_id, db)
    return await site_service.get_sites(db=db, tenant_id=tenant_id)


@router.get(
    "/tenants/{tenant_id}/sites/{site_id}",
    response_model=SiteResponse,
    summary="Get site details",
)
async def get_site(
    tenant_id: uuid.UUID,
    site_id: uuid.UUID,
    current_user: CurrentUser = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> SiteResponse:
    """Get a single site with health rollup. Viewer role and above."""
    await _check_tenant_access(current_user, tenant_id, db)
    return await site_service.get_site(db=db, tenant_id=tenant_id, site_id=site_id)


@router.post(
    "/tenants/{tenant_id}/sites",
    response_model=SiteResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create a site",
    dependencies=[Depends(require_operator_or_above)],
)
async def create_site(
    tenant_id: uuid.UUID,
    data: SiteCreate,
    current_user: CurrentUser = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> SiteResponse:
    """Create a new site. Requires operator role or above."""
    await _check_tenant_access(current_user, tenant_id, db)
    return await site_service.create_site(
        db=db, tenant_id=tenant_id, data=data, user_id=current_user.id
    )


@router.put(
    "/tenants/{tenant_id}/sites/{site_id}",
    response_model=SiteResponse,
    summary="Update a site",
    dependencies=[Depends(require_operator_or_above)],
)
async def update_site(
    tenant_id: uuid.UUID,
    site_id: uuid.UUID,
    data: SiteUpdate,
    current_user: CurrentUser = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> SiteResponse:
    """Update a site. Requires operator role or above."""
    await _check_tenant_access(current_user, tenant_id, db)
    return await site_service.update_site(
        db=db, tenant_id=tenant_id, site_id=site_id, data=data, user_id=current_user.id
    )


@router.delete(
    "/tenants/{tenant_id}/sites/{site_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Delete a site",
    dependencies=[Depends(require_tenant_admin_or_above)],
)
async def delete_site(
    tenant_id: uuid.UUID,
    site_id: uuid.UUID,
    current_user: CurrentUser = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> None:
    """Delete a site. Requires tenant_admin or above."""
    await _check_tenant_access(current_user, tenant_id, db)
    await site_service.delete_site(
        db=db, tenant_id=tenant_id, site_id=site_id, user_id=current_user.id
    )


# ---------------------------------------------------------------------------
# Device assignment
# ---------------------------------------------------------------------------


@router.post(
    "/tenants/{tenant_id}/sites/{site_id}/devices/{device_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Assign device to site",
    dependencies=[Depends(require_operator_or_above)],
)
async def assign_device(
    tenant_id: uuid.UUID,
    site_id: uuid.UUID,
    device_id: uuid.UUID,
    current_user: CurrentUser = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> None:
    """Assign a single device to a site. Requires operator role or above."""
    await _check_tenant_access(current_user, tenant_id, db)
    await site_service.assign_device_to_site(
        db=db, tenant_id=tenant_id, site_id=site_id, device_id=device_id
    )


@router.delete(
    "/tenants/{tenant_id}/sites/{site_id}/devices/{device_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Remove device from site",
    dependencies=[Depends(require_operator_or_above)],
)
async def unassign_device(
    tenant_id: uuid.UUID,
    site_id: uuid.UUID,
    device_id: uuid.UUID,
    current_user: CurrentUser = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> None:
    """Remove a device from a site. Requires operator role or above."""
    await _check_tenant_access(current_user, tenant_id, db)
    await site_service.remove_device_from_site(
        db=db, tenant_id=tenant_id, device_id=device_id
    )


@router.post(
    "/tenants/{tenant_id}/sites/{site_id}/devices/bulk-assign",
    summary="Bulk assign devices to site",
    dependencies=[Depends(require_operator_or_above)],
)
async def bulk_assign_devices(
    tenant_id: uuid.UUID,
    site_id: uuid.UUID,
    body: BulkAssignRequest,
    current_user: CurrentUser = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> dict:
    """Bulk-assign multiple devices to a site. Requires operator role or above."""
    await _check_tenant_access(current_user, tenant_id, db)
    count = await site_service.bulk_assign_devices_to_site(
        db=db, tenant_id=tenant_id, site_id=site_id, device_ids=body.device_ids
    )
    return {"assigned": count}
