"""
responses.py
-------------
Pydantic response models for the HIEROMEM API.

Defines structured responses for:
  • Episodic memory operations (remember, recall, forget)
  • Governance and GSR inspection
  • Metrics and health endpoints
  • Event narration and timeline introspection

Author: Sai Rishi Kiran Mannava
"""

from __future__ import annotations
from typing import Any, Optional, List
from pydantic import BaseModel, Field


# --------------------------------------------------------------------------- #
# Base primitives
# --------------------------------------------------------------------------- #


class EpisodeSummary(BaseModel):
    """
    Lightweight representation of an episode returned by recall or dump.
    """

    id: str = Field(..., description="Unique episode identifier.")
    trust: float = Field(..., ge=0.0, le=1.0, description="Current trust score.")
    timestamp: str = Field(..., description="Timestamp of occurrence (ISO format).")
    text: Optional[str] = Field(default=None, description="Raw episode content, when available.")
    meta: Optional[dict[str, Any]] = Field(default=None, description="Episode metadata tags.")


class TreeItem(BaseModel):
    """
    Lightweight episode node for hierarchy visualization.
    """
    id: str = Field(..., description="Episode identifier.")
    parent: Optional[str] = Field(default=None,
                                  description="Parent episode identifier.")
    trust: float = Field(..., description="Trust score.")
    tocc: str = Field(..., description="Creation timestamp.")
    meta: Optional[dict[str, Any]] = Field(
        default=None, description="Metadata tags.")


class GraphNode(BaseModel):
    id: str
    # Allow arbitrary node attributes

    class Config:
        extra = "allow"


class GraphEdge(BaseModel):
    u: str
    v: str
    # Allow arbitrary edge attributes

    class Config:
        extra = "allow"


class EpisodeGraph(BaseModel):
    nodes: list[dict[str, Any]]
    edges: list[dict[str, Any]]


class EpisodeDetail(EpisodeSummary):
    """
    Full episode details including graph and embedding.
    """
    e: list[float] = Field(..., description="Embedding vector.")
    G: EpisodeGraph = Field(..., description="Scene graph structure.")
    parent: Optional[str] = Field(
        default=None, description="Parent episode ID.")


class DegradationStatus(BaseModel):
    """Represents a forced degradation window for health/readiness probes."""

    active: bool = Field(..., description="Whether a manual degradation is active.")
    reason: Optional[str] = Field(
        default=None, description="Operator-supplied reason for the override."
    )
    expires_at: Optional[str] = Field(
        default=None, description="ISO timestamp when the override will clear."
    )


class HealthResponse(BaseModel):
    status: str
    episodes: int
    backend: str
    gsr_safe: bool
    degradation: Optional[DegradationStatus] = None


class ReadinessResponse(BaseModel):
    status: str
    backend: bool
    encoder: bool
    events: bool
    degradation: Optional[DegradationStatus] = None


class InfoResponse(BaseModel):
    status: str
    backend: Optional[str]
    multi_tenant: bool
    namespaces: list[str]
    gsr_safe: bool
    parameters: dict[str, float]
    debug: bool
    version: str


class ConfigSnapshotResponse(BaseModel):
    """Configuration snapshot response model.

    Fields:
        status: overall status string (e.g., "ok")
        active_backend: name of the active symbolic backend, if any
        config: sanitized configuration dictionary
        env: deployment environment identifier
    """
    status: str = Field(..., description="Overall status of the config snapshot.")
    active_backend: Optional[str] = Field(None, description="Active symbolic backend name.")
    config: dict[str, Any] = Field(..., description="Sanitized configuration values.")
    env: str = Field(..., description="Environment identifier (e.g., dev, prod).")


# Memory operation responses
class RememberResponse(BaseModel):
    episode_id: str
    trust: float
    message: str


class RecallResponse(BaseModel):
    results: list[EpisodeSummary]
    query: str
    k: int


class ForgetResponse(BaseModel):
    status: str
    message: str
    removed_ids: list[str] | None = None


class MetricResponse(BaseModel):
    total_episodes: int
    avg_trust: float
    gsr_valid: bool
    summary_distortion: float
    distortion_bound: float
    contraction_factor: float
    lyapunov_margin: float
    lyapunov_warning: bool
    uptime_s: float
    namespace: Optional[str] = None
    symbolic_inconsistencies: Optional[dict[str, Any]] = None
    symbolic_namespace_summaries: Optional[dict[str, Any]] = None
    activity: Optional[dict[str, float]] = None
    persistence: Optional[dict[str, Any]] = None


class DualRecallEpisode(BaseModel):
    id: str
    trust: float
    timestamp: str
    text: str
    meta: Optional[dict[str, Any]] = None
    dense_score: float = 0.0
    symbolic_score: float = 0.0
    combined_score: float = 0.0


class DualRecallResponse(BaseModel):
    episodic: list[DualRecallEpisode]
    symbolic: list[str]
    query: str
    namespace: Optional[str] = None
    k: int
    alpha_dense: Optional[float] = None
    beta_symbolic: Optional[float] = None
    lambda_decay: Optional[float] = None
    temperature: Optional[float] = None
    iterations: int
    embedding_provided: bool = False
    dense_scores: dict[str, float]
    symbolic_scores: dict[str, float]
    combined_weights: dict[str, float]
    insights: list[str] = []


class SymbolicMatch(BaseModel):
    entity: str
    relation: str
    target: str
    confidence: float


class SymbolicSearchResponse(BaseModel):
    namespace: Optional[str] = None
    path: Optional[list[str]] = None
    pattern_edges: Optional[list[tuple[str, str]]] = None
    results: list[SymbolicMatch]


class BatchDualRecallItem(BaseModel):
    query: str
    episodic: list[DualRecallEpisode]
    symbolic: list[str]


# --------------------------------------------------------------------------- #
# Policy responses
# --------------------------------------------------------------------------- #


class PolicyDocument(BaseModel):
    name: str
    namespace: Optional[str] = None
    policy: dict[str, Any]


class PolicyUpsertResponse(BaseModel):
    status: str
    document: PolicyDocument


class PolicyListResponse(BaseModel):
    policies: list[PolicyDocument]


class PolicyDecisionResponse(BaseModel):
    action: str
    allowed: bool
    reasons: list[str]
    metadata: dict[str, Any]


class PolicySimulationResponse(BaseModel):
    namespace: Optional[str] = None
    insert: PolicyDecisionResponse
    summarise: PolicyDecisionResponse
    retention_candidates: list[str]


class BatchDualRecallResponse(BaseModel):
    results: list[BatchDualRecallItem]


class BatchSymbolicSearchItem(BaseModel):
    query: str
    matches: list[SymbolicMatch]


class BatchSymbolicSearchResponse(BaseModel):
    results: list[BatchSymbolicSearchItem]


# Event and narration responses
class EventRecord(BaseModel):
    idx: int | None = None
    event_type: str
    message: str
    timestamp: str
    level: str = "info"
    duration: float | None = None
    source: str | None = None
    session_id: str | None = None
    episode_id: str | None = None
    details: dict[str, Any] | None = None


class NarrationResponse(BaseModel):
    mode: str
    narration: str


# Admin and governance responses
class GSRViewResponse(BaseModel):
    region: dict[str, float]
    is_valid: bool
    risk_level: str
    bounds: dict[str, list[float]]


class ParamUpdateResponse(BaseModel):
    status: str
    message: str
    updated: dict[str, Any]
    gsr_valid: bool
    gsr: dict[str, Any]


# Export public symbols

class RealmResponse(BaseModel):
    name: str
    type: str
    participants: List[dict]
    isolation_level: str
    count: Optional[int] = 0


__all__ = [
    "EpisodeSummary",
    "TreeItem",
    "GraphNode",
    "GraphEdge",
    "EpisodeGraph",
    "EpisodeDetail",
    "ConfigSnapshotResponse",
    "HealthResponse",
    "InfoResponse",
    "ReadinessResponse",
    "RememberResponse",
    "RecallResponse",
    "ForgetResponse",
    "MetricResponse",
    "DualRecallEpisode",
    "DualRecallResponse",
    "SymbolicMatch",
    "SymbolicSearchResponse",
    "BatchDualRecallItem",
    "BatchDualRecallResponse",
    "BatchSymbolicSearchItem",
    "BatchSymbolicSearchResponse",
    "EventRecord",
    "NarrationResponse",
    "GSRViewResponse",
    "ParamUpdateResponse",
    "RealmResponse",
]
