"""Fastlane → Webhook / Status Driver.

Fastlane posts to this endpoint whenever an asset support process completes
or is reverted (spec §5.1 / §5.2). The webhook does not call any downstream
service directly — it validates the shared key and publishes the status event
to Kafka so multiple consumers (Status Listener, Analytics, Audit, …) can
subscribe independently.
"""
from typing import Any

from fastapi import APIRouter, HTTPException, Request, status

from ..config import get_settings
from ..kafka_client import get_producer
from ..logger import get_logger
from ..schemas import (
    AllocationStatus,
    FastlaneNotification,
    TankAllocationStatusEvent,
)

router = APIRouter(prefix="/webhook", tags=["webhook"])
log = get_logger(__name__)


def _map_status(notification: FastlaneNotification) -> AllocationStatus | None:
    """Map Fastlane notification type+status → our AllocationStatus.

    §5.1 asset:reviewCompleted  → approved  = COMPLETED (green tick)
                                   rejected  = FAILED    (red cross)
    §5.2 asset:reviewReverted   → committed = PENDING   (amber clock — back to waiting)
    """
    t = notification.type
    s = (notification.payload.status or "").lower()
    if t == "asset:reviewCompleted":
        if s == "approved":
            return AllocationStatus.COMPLETED
        if s == "rejected":
            return AllocationStatus.FAILED
    if t == "asset:reviewReverted":
        # §5.2: status returns to "committed" (waiting for approval again)
        # → treat as PENDING, not BLOCKED
        return AllocationStatus.PENDING
    return None


@router.post("/fastlane", status_code=status.HTTP_202_ACCEPTED)
async def fastlane_webhook(request: Request) -> dict[str, Any]:
    """Receive Fastlane notification and publish to Kafka."""
    settings = get_settings()
    body = await request.json()

    # --- 1. Auth ----------------------------------------------------------
    # §1.7 Standard mode: BASF sends our ERP key inside body.publicKey.
    # We accept it there. An optional X-Webhook-Secret header is a secondary
    # guard for extra protection.
    provided_key  = body.get("publicKey")
    header_secret = request.headers.get("X-Webhook-Secret")
    if provided_key != settings.fastlane_erp_key and header_secret != settings.webhook_secret:
        log.warning("Rejecting Fastlane webhook: invalid credentials")
        raise HTTPException(status_code=401, detail="Invalid credentials")

    # --- 2. Parse ---------------------------------------------------------
    try:
        note = FastlaneNotification.model_validate(body)
    except Exception as e:  # noqa: BLE001
        log.exception("Malformed Fastlane webhook body: %s", e)
        raise HTTPException(status_code=422, detail="Malformed payload") from e

    mapped = _map_status(note)
    if mapped is None:
        log.info("Ignoring Fastlane event type=%s status=%s",
                 note.type, note.payload.status)
        return {"received": True, "published": False, "reason": "unmapped"}

    # --- 3. Choose target Kafka topic ------------------------------------
    # reviewReverted (PENDING) re-uses topic_allocate_completed; the status
    # field value tells the status_listener / ERP callback it's still waiting.
    topic_attr = {
        AllocationStatus.COMPLETED: "topic_allocate_completed",
        AllocationStatus.FAILED: "topic_allocate_failed",
        AllocationStatus.BLOCKED: "topic_allocate_blocked",
        AllocationStatus.PENDING: "topic_allocate_completed",  # reviewReverted — back to waiting
    }[mapped]
    topic = getattr(settings, topic_attr)

    event = TankAllocationStatusEvent(
        event_type=topic,
        status=mapped,
        fastlane_id=note.payload.id,
        licence_number=note.payload.licence_number,
        nationality=note.payload.nationality,
        incremental_version=note.payload.incrementalVersion,
        message=note.payload.reviewDetails,
        raw=body,
    )

    # --- 4. Publish -------------------------------------------------------
    producer = await get_producer()
    key = str(note.payload.id) if note.payload.id is not None else (
        note.payload.licence_number or "unknown"
    )
    await producer.publish(topic=topic, key=key, value=event.model_dump(mode="json"))

    log.info(
        "Webhook published %s for fastlane_id=%s plate=%s status=%s",
        topic, note.payload.id, note.payload.licence_number, mapped,
    )

    return {"received": True, "published": True, "topic": topic}
