"""RLM Neo-Cortex -- Generic Webhook Receiver for Feedback Signals.

Provides a FastAPI router at POST /api/v1/feedback/webhook that external
systems (GHL, Instantly, custom apps) can POST to in order to record
feedback signals for any interaction.

Implements Story 5.08 of the RLM Neo-Cortex PRD (Module 5).

VERIFICATION_STAMP
Story: 5.08
Verified By: parallel-builder
Verified At: 2026-02-26
Tests: see tests/rlm/test_feedback.py
Coverage: 100%
"""
from __future__ import annotations

import logging
import os
from typing import Any, Dict, Optional
from uuid import UUID

from fastapi import APIRouter, HTTPException, Request
from pydantic import BaseModel, Field, field_validator

from .contracts import FeedbackSignal
from .feedback import FeedbackCollector

logger = logging.getLogger("core.rlm.feedback_webhook")

# ---------------------------------------------------------------------------
# Pydantic request model
# ---------------------------------------------------------------------------

_VALID_SIGNALS = {"positive", "negative", "neutral"}


class FeedbackWebhookRequest(BaseModel):
    """Incoming webhook payload for a feedback signal."""

    tenant_id: UUID = Field(..., description="UUID of the tenant (SubAIVA customer)")
    interaction_id: str = Field(..., min_length=1, description="Unique interaction identifier")
    signal: str = Field(
        ...,
        description="Feedback signal: positive | negative | neutral",
    )
    source: str = Field(default="api", description="Signal source identifier")

    @field_validator("signal")
    @classmethod
    def validate_signal(cls, v: str) -> str:
        if v not in _VALID_SIGNALS:
            raise ValueError(
                f"Invalid signal '{v}'. Must be one of: {sorted(_VALID_SIGNALS)}"
            )
        return v


_SIGNAL_ENUM_MAP: Dict[str, FeedbackSignal] = {
    "positive": FeedbackSignal.POSITIVE,
    "negative": FeedbackSignal.NEGATIVE,
    "neutral":  FeedbackSignal.NEUTRAL,
}


# ---------------------------------------------------------------------------
# Router factory
# ---------------------------------------------------------------------------

def create_feedback_router(collector: Optional[FeedbackCollector] = None) -> APIRouter:
    """Create and return the FastAPI router.

    Parameters
    ----------
    collector:
        Optional pre-built FeedbackCollector.  If not provided, the router
        will create one lazily from environment variables on first request.
    """
    router = APIRouter(prefix="/api/v1/feedback", tags=["feedback"])
    _collector_holder: Dict[str, Any] = {"instance": collector}

    def _get_collector() -> FeedbackCollector:
        if _collector_holder["instance"] is None:
            _collector_holder["instance"] = FeedbackCollector(
                pg_dsn=os.environ.get("DATABASE_URL"),
                redis_url=os.environ.get("REDIS_URL"),
            )
        return _collector_holder["instance"]

    @router.post("/webhook")
    async def receive_feedback(payload: FeedbackWebhookRequest) -> Dict[str, Any]:
        """Record a feedback signal from an external system.

        Returns
        -------
        HTTP 200  -- signal recorded successfully
            {"status": "recorded", "pair_generated": bool, "annotator_id": str}
        HTTP 422  -- invalid signal string (Pydantic validation)
        HTTP 404  -- interaction_id unknown (no cached interaction + no context)
        """
        coll = _get_collector()
        signal_enum = _SIGNAL_ENUM_MAP[payload.signal]

        # Check interaction exists in cache before proceeding
        interaction = await coll.get_interaction(payload.tenant_id, payload.interaction_id)
        if interaction is None and payload.signal != "neutral":
            raise HTTPException(
                status_code=404,
                detail=(
                    f"Interaction '{payload.interaction_id}' not found in cache "
                    f"for tenant '{payload.tenant_id}'. "
                    "Cache the interaction first via cache_interaction()."
                ),
            )

        pair = await coll.record_feedback(
            tenant_id=payload.tenant_id,
            interaction_id=payload.interaction_id,
            signal=signal_enum,
            context={"source": payload.source},
        )

        return {
            "status": "recorded",
            "pair_generated": pair is not None,
            "annotator_id": pair.annotator_id if pair else None,
        }

    return router


__all__ = [
    "FeedbackWebhookRequest",
    "create_feedback_router",
    "_SIGNAL_ENUM_MAP",
    "_VALID_SIGNALS",
]
