"""CRUD API для insight (#948 Part A, ТЗ §7.13/§8.9).

POST   /api/v1/insights        → 201 InsightOut          (create)
GET    /api/v1/insights        → InsightList             (list + filters + pagination)
GET    /api/v1/insights/{id}   → InsightOut              (one; 404 если нет)
PUT    /api/v1/insights/{id}   → InsightOut              (partial update; 404 если нет)
DELETE /api/v1/insights/{id}   → 204                     (hard delete; 404 если нет)

Access control: backend rbac_guard (app/main.py) хард-блокирует ТОЛЬКО
/api/v1/admin/* (admin-only). На /api/v1/insights pilot отсекается FRONTEND-овым
RouteGuard (allowed_paths из /me) + Caddy, НЕ бэкендом — is_path_allowed() из
backend-кода не вызывается. До эндпоинта доходят analyst+admin. is_confidential —
хранимая маркировка (per-record backend-gate НЕТ), политика #962: analyst видит
конфиденциальные данные. created_by автора берём из X-Authenticated-User (тот же
заголовок, что Caddy basic_auth пробрасывает в backend) — НЕ из тела запроса.

Хэндлеры sync `def` (зеркало custom_pois.py): сервис ходит в БД через sync
SQLAlchemy Session, поэтому FastAPI исполняет их в threadpool — event loop не
блокируется. (Делать async def + sync db.execute было бы хуже — заблокировало
бы loop.)

Audit (§19): WRITE-запросы (POST/PUT/DELETE) аудируются HTTP-middleware
app/core/audit_middleware.py как action='insight_write' — здесь спец-кода нет.
"""

from __future__ import annotations

import logging
from typing import Annotated, Any

from fastapi import APIRouter, Depends, Header, HTTPException, Query, status
from sqlalchemy.orm import Session

from app.core.db import get_db
from app.schemas.insight import (
    InsightCategory,
    InsightCreate,
    InsightList,
    InsightOut,
    InsightUpdate,
)
from app.services.insights import (
    create_insight,
    delete_insight,
    get_insight,
    list_insights,
    update_insight,
)

logger = logging.getLogger(__name__)

router = APIRouter()


def _require_user(x_authenticated_user: str | None) -> str:
    """Вернуть автора из X-Authenticated-User или 401.

    В проде Caddy basic_auth всегда пробрасывает заголовок для авторизованных,
    а rbac_guard рубит запросы без него ещё до роутера. Эта проверка — defence
    in depth (+ корректный ответ в test-mode, где rbac_guard выключен).
    """
    if x_authenticated_user and x_authenticated_user.strip():
        return x_authenticated_user.strip()
    raise HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="no authenticated user (X-Authenticated-User required)",
    )


@router.post("", response_model=InsightOut, status_code=status.HTTP_201_CREATED)
def create_insight_endpoint(
    payload: InsightCreate,
    db: Annotated[Session, Depends(get_db)],
    x_authenticated_user: Annotated[str | None, Header()] = None,
) -> Any:
    """Создать insight. created_by = X-Authenticated-User."""
    created_by = _require_user(x_authenticated_user)
    return create_insight(db, created_by, payload)


@router.get("", response_model=InsightList)
def list_insights_endpoint(
    db: Annotated[Session, Depends(get_db)],
    district: Annotated[str | None, Query(description="Фильтр по району")] = None,
    cad_num: Annotated[str | None, Query(description="Фильтр по кадастровому номеру")] = None,
    category: Annotated[InsightCategory | None, Query(description="Фильтр по категории")] = None,
    is_confidential: Annotated[
        bool | None, Query(description="Фильтр по пометке «непублично»")
    ] = None,
    created_by: Annotated[str | None, Query(description="Фильтр по автору")] = None,
    limit: Annotated[int, Query(ge=1, le=200)] = 50,
    offset: Annotated[int, Query(ge=0)] = 0,
) -> Any:
    """Список insight'ов с фильтрами + пагинацией."""
    return list_insights(
        db,
        district=district,
        cad_num=cad_num,
        category=category,
        is_confidential=is_confidential,
        created_by=created_by,
        limit=limit,
        offset=offset,
    )


@router.get("/{insight_id}", response_model=InsightOut)
def get_insight_endpoint(
    insight_id: int,
    db: Annotated[Session, Depends(get_db)],
) -> Any:
    """Вернуть один insight. 404 если не найден."""
    insight = get_insight(db, insight_id)
    if insight is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Insight not found")
    return insight


@router.put("/{insight_id}", response_model=InsightOut)
def update_insight_endpoint(
    insight_id: int,
    payload: InsightUpdate,
    db: Annotated[Session, Depends(get_db)],
    x_authenticated_user: Annotated[str | None, Header()] = None,
) -> Any:
    """Partial update insight. 404 если не найден."""
    _require_user(x_authenticated_user)
    insight = update_insight(db, insight_id, payload)
    if insight is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Insight not found")
    return insight


@router.delete("/{insight_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_insight_endpoint(
    insight_id: int,
    db: Annotated[Session, Depends(get_db)],
    x_authenticated_user: Annotated[str | None, Header()] = None,
) -> None:
    """Удалить insight. 404 если не найден."""
    _require_user(x_authenticated_user)
    deleted = delete_insight(db, insight_id)
    if not deleted:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Insight not found")
