"""
routes/fraud.py — Fraud Detection
POST /api/fraud/event              — log a fraud event (JWT-authed candidate)
POST /api/fraud/event-by-key       — log a fraud event keyed by access_key
                                     (new external-login flow)
GET  /api/fraud/report             — fraud report for the authenticated candidate
GET  /api/fraud/report-by-key/{k}  — fraud report by access_key
GET  /api/admin/fraud/all          — admin: all fraud events
"""
from __future__ import annotations

from datetime import datetime, timezone
from typing import Any

from fastapi import APIRouter, Depends
from pydantic import BaseModel, Field

from config import settings
from models.schemas import FraudEventRequest, FraudEventResponse, SuccessResponse
from services.fraud_service import fraud_service
from middleware.auth_middleware import get_current_candidate
from utils import json_db as db
from utils.logger import get_logger

log = get_logger(__name__)
router = APIRouter(tags=["fraud"])


# ── Authenticated path (legacy / internal) ────────────────────────────────────

@router.post("/api/fraud/event", response_model=FraudEventResponse)
async def log_fraud_event(
    body: FraudEventRequest,
    candidate: dict = Depends(get_current_candidate),
):
    """Log a fraud event for the JWT-authenticated candidate."""
    access_key = candidate.get("access_key") or candidate.get("id") or ""
    result = await fraud_service.log_event(
        candidate_id=candidate["id"],
        event_type=body.event_type,
        message=body.message,
        timestamp=body.timestamp,
        round_num=body.round,
        metadata={**(body.metadata or {}), "access_key": access_key},
    )
    return FraudEventResponse(**result)


@router.get("/api/fraud/report", response_model=SuccessResponse)
def fraud_report(candidate: dict = Depends(get_current_candidate)):
    return SuccessResponse(data=fraud_service.get_report(candidate["id"]))


# ── Access-key path (new external login flow) ─────────────────────────────────

class FraudEventByKeyRequest(BaseModel):
    event_type: str             = Field(..., description="TAB_SWITCH | PASTE | MULTIPLE_FACES | …")
    message: str                = ""
    timestamp: str | None       = None
    round: int                  = 1
    metadata: dict[str, Any] | None = None


def _now_iso() -> str:
    return datetime.now(timezone.utc).isoformat()


@router.post("/api/fraud/event-by-key/{access_key}")
async def log_fraud_event_by_key(access_key: str, body: FraudEventByKeyRequest):
    """
    Log a fraud event keyed by access_key — for candidates authenticated
    via the external People Hub Login API (no local JWT).

    Per spec, every event written to fraud_log.json must carry:
      • access_key
      • event type
      • timestamp

    The fraud_service in-memory counters still drive `action` (none/warn/
    disqualify), keyed off the access_key as the candidate identifier.
    """
    key = (access_key or "").strip()
    if not key:
        return {"ok": False, "error": "access_key required"}

    ts = body.timestamp or _now_iso()
    result = await fraud_service.log_event(
        candidate_id=key,                     # access_key doubles as the id
        event_type=body.event_type,
        message=body.message,
        timestamp=ts,
        round_num=body.round,
        metadata={**(body.metadata or {}), "access_key": key},
    )

    # Defensive: ensure access_key is present in the persisted record. The
    # fraud_service already inserts via json_db; we patch the latest row to
    # add an explicit top-level access_key field so it's queryable.
    try:
        events = db.find_all(settings.FRAUD_LOG_FILE)
        if events:
            last = events[-1]
            if last.get("candidate_id") == key and not last.get("access_key"):
                db.update(settings.FRAUD_LOG_FILE, last["id"], {"access_key": key})
    except Exception as exc:  # noqa: BLE001
        log.debug("post-write access_key tag failed (non-fatal): %s", exc)

    return {"ok": True, **result}


@router.get("/api/fraud/report-by-key/{access_key}", response_model=SuccessResponse)
def fraud_report_by_key(access_key: str):
    key = (access_key or "").strip()
    if not key:
        return SuccessResponse(data={})
    return SuccessResponse(data=fraud_service.get_report(key))


# ── Admin ─────────────────────────────────────────────────────────────────────

@router.get("/api/admin/fraud/all", response_model=SuccessResponse)
def all_fraud_events(candidate_id: str | None = None, access_key: str | None = None):
    """
    Admin: get all fraud events, optionally filtered by candidate_id or
    access_key. Protect with admin JWT in production.
    """
    if access_key:
        events = db.find_many(settings.FRAUD_LOG_FILE, access_key=access_key)
    elif candidate_id:
        events = db.find_many(settings.FRAUD_LOG_FILE, candidate_id=candidate_id)
    else:
        events = db.find_all(settings.FRAUD_LOG_FILE)
    return SuccessResponse(data=events)
