"""RequestAuditMiddleware — пишет `api_request` (+ дедуплицированный `login`)
события в `user_events` для каждого аутентифицированного `/api/*` запроса.

Foundation для Feature 2 (login/IP audit) и базы Feature 3 (behavior analytics).
Логирование выполняется ПОСЛЕ `call_next` (не задерживает и не ветвит реальный
ответ клиенту) и через fire-and-forget `schedule_event` — сбой аудита никогда
не влияет на HTTP-ответ.
"""

from __future__ import annotations

import logging

from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response

from app.core.ratelimit import _client_ip
from app.services.user_events import schedule_event, should_log_login

logger = logging.getLogger(__name__)

# Зеркалит app.main._PUBLIC_PATHS. Не импортируем напрямую из app.main — оно
# импортирует этот модуль (регистрирует middleware), обратный импорт дал бы
# циклическую зависимость.
_PUBLIC_PATHS = frozenset({"/health", "/docs", "/redoc", "/openapi.json"})


class RequestAuditMiddleware(BaseHTTPMiddleware):
    """Логирует активность аутентифицированных пользователей в `user_events`."""

    async def dispatch(self, request: Request, call_next):  # type: ignore[no-untyped-def]
        response: Response = await call_next(request)

        try:
            username = request.headers.get("x-authenticated-user")
            path = request.url.path
            if username and path.startswith("/api/") and path not in _PUBLIC_PATHS:
                ip = _client_ip(request)
                ua = request.headers.get("user-agent")

                # Общий behavior/activity-поток — каждый authenticated API-запрос.
                # /api/v1/admin/* исключаем: это ops-действия (просмотр самих
                # дашбордов аудита/аналитики), а не поведение пилота — иначе
                # запросы дашборда зашумляют top_paths и счётчики активности.
                # login ниже логируем всегда (вход админа с IP — валидный аудит).
                if not path.startswith("/api/v1/admin/"):
                    schedule_event(
                        event_type="api_request",
                        username=username,
                        ip=ip,
                        user_agent=ua,
                        path=path,
                        method=request.method,
                    )

                # Дедуплицированный login/IP-audit сигнал — максимум раз в день
                # на (юзер, IP, устройство).
                if should_log_login(username, ip, ua):
                    schedule_event(
                        event_type="login",
                        username=username,
                        ip=ip,
                        user_agent=ua,
                        path=path,
                        method=request.method,
                    )
        except Exception:
            logger.warning("RequestAuditMiddleware: failed to record event", exc_info=True)

        return response
