"""Norms BFF — proxies normbase with field/org checks."""

from __future__ import annotations

import uuid
from typing import Annotated, Any

from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, Response, status

from aif_platform.server.api.deps import get_normbase_client, get_org_context
from aif_platform.server.infra.upstream import NormbaseClient
from aif_platform.server.models.persistence import PlatformUser
from aif_platform.server.services.access import require_field_in_org, require_norm_in_org
from aif_platform.server.services.field_api_key_http import extract_field_api_key
from security.auth.core import AuthInput, authorize, resolve_integration_api_key

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


@router.get("")
async def list_norms(
    ctx: tuple[PlatformUser, uuid.UUID] = Depends(get_org_context),
    nb: NormbaseClient = Depends(get_normbase_client),
    field_id: uuid.UUID = Query(..., description="Required: norms are listed in a field context."),
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    norm_type: str | None = None,
    norm_status: str | None = Query(None, alias="status"),
    authority_level: str | None = None,
    formality_level: str | None = None,
    governed_aspect: str | None = None,
):
    _user, org_id = ctx
    await require_field_in_org(nb, field_id=field_id, org_id=org_id)
    params: dict[str, Any] = {
        "page": page,
        "page_size": page_size,
        "field_id": str(field_id),
    }
    if norm_type is not None:
        params["norm_type"] = norm_type
    if norm_status is not None:
        params["status"] = norm_status
    if authority_level is not None:
        params["authority_level"] = authority_level
    if formality_level is not None:
        params["formality_level"] = formality_level
    if governed_aspect is not None:
        params["governed_aspect"] = governed_aspect
    return await nb.list_norms(params)


@router.post("", status_code=201)
async def create_norm(
    body: dict[str, Any] = Body(...),
    ctx: tuple[PlatformUser, uuid.UUID] = Depends(get_org_context),
    nb: NormbaseClient = Depends(get_normbase_client),
):
    _user, org_id = ctx
    fid = body.get("field_id")
    if not fid:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="field_id is required.",
        )
    await require_field_in_org(nb, field_id=uuid.UUID(str(fid)), org_id=org_id)
    return await nb.create_norm(body)


@router.post("/field-import", status_code=201)
async def import_norms_with_field_key(
    body: dict[str, Any] = Body(...),
    nb: NormbaseClient = Depends(get_normbase_client),
    authorization: Annotated[str | None, Header()] = None,
    x_field_api_key: Annotated[str | None, Header(alias="X-Field-API-Key")] = None,
):
    """Create draft norms in the key-bound field using a Field API key (norms:import scope)."""
    plain = extract_field_api_key(authorization, x_field_api_key)
    if not plain:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Missing field API key (X-Field-API-Key or Bearer aif_fk_…).",
        )
    auth = await authorize(
        AuthInput(
            entry_type="sdk",
            api_key=plain,
            action="norms:field_import",
            required_scopes=["norms:import"],
        ),
        resolver=resolve_integration_api_key,
    )
    if auth.decision != "allow" or auth.key_kind != "field" or not (auth.field_id or "").strip():
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or insufficient field API key.",
        )
    field_uuid = uuid.UUID(auth.field_id)
    fields = await nb.list_fields()
    if not isinstance(fields, list):
        raise HTTPException(status_code=status.HTTP_502_BAD_GATEWAY, detail="Invalid fields response.")
    match = next((x for x in fields if isinstance(x, dict) and str(x.get("id")) == str(field_uuid)), None)
    if not match:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Field not found.")
    field_org = match.get("org_id")
    if field_org is None or str(field_org).strip() != (auth.org_id or "").strip():
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Field API key does not match field organization.",
        )

    raw_items = body.get("norms")
    if not isinstance(raw_items, list) or not raw_items:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Body must include a non-empty 'norms' array.",
        )
    created: list[Any] = []
    for i, item in enumerate(raw_items):
        if not isinstance(item, dict):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"norms[{i}] must be an object.",
            )
        payload = {**item, "field_id": str(field_uuid)}
        if not payload.get("created_by"):
            payload["created_by"] = f"external:field_key:{auth.key_id}"
        try:
            created.append(await nb.create_norm(payload))
        except HTTPException as exc:
            raise HTTPException(
                status_code=exc.status_code,
                detail={"message": str(exc.detail), "index": i},
            ) from exc
    return {"items": created, "count": len(created)}


@router.get("/{norm_id}")
async def get_norm(
    norm_id: uuid.UUID,
    ctx: tuple[PlatformUser, uuid.UUID] = Depends(get_org_context),
    nb: NormbaseClient = Depends(get_normbase_client),
):
    _user, org_id = ctx
    return await require_norm_in_org(nb, norm_id=norm_id, org_id=org_id)


@router.put("/{norm_id}")
async def update_norm(
    norm_id: uuid.UUID,
    body: dict[str, Any] = Body(...),
    ctx: tuple[PlatformUser, uuid.UUID] = Depends(get_org_context),
    nb: NormbaseClient = Depends(get_normbase_client),
):
    _user, org_id = ctx
    await require_norm_in_org(nb, norm_id=norm_id, org_id=org_id)
    if "field_id" in body and body["field_id"] is not None:
        await require_field_in_org(nb, field_id=uuid.UUID(str(body["field_id"])), org_id=org_id)
    return await nb.update_norm(norm_id, body)


@router.delete("/{norm_id}")
async def delete_norm(
    norm_id: uuid.UUID,
    ctx: tuple[PlatformUser, uuid.UUID] = Depends(get_org_context),
    nb: NormbaseClient = Depends(get_normbase_client),
):
    _user, org_id = ctx
    await require_norm_in_org(nb, norm_id=norm_id, org_id=org_id)
    await nb.delete_norm(norm_id)
    return Response(status_code=status.HTTP_204_NO_CONTENT)
