"""
SQLAlchemy 2.0 ORM models for conversational memory.

ConversationEmbedding stores pgvector embeddings of past conversation turns
for long-term semantic retrieval across sessions. This is the persistence layer
for the long-term memory module in the Agent Orchestrator.

IMPORTANT:
- Embeddings are immutable (no UPDATE) — like audit records. We store and read
  but never modify. This simplifies the data model and prevents mutation bugs.
- RLS is ENABLED with FORCE — tenant_id isolation is enforced at the DB level.
- The vector dimension (384) corresponds to all-MiniLM-L6-v2 output size.
"""

from __future__ import annotations

import uuid
from datetime import datetime

from pgvector.sqlalchemy import Vector
from sqlalchemy import DateTime, ForeignKey, Text, func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column

from shared.models.tenant import Base


class ConversationEmbedding(Base):
    """
    A single embedded conversation turn stored for long-term recall.

    Each row represents one message (user or assistant) converted to a
    384-dimensional embedding via all-MiniLM-L6-v2. The Agent Orchestrator
    queries this table at prompt assembly time to inject relevant past context.

    Scoped by:
      - tenant_id: RLS enforced isolation between tenants
      - agent_id: isolation between agents within a tenant
      - user_id: isolation between end-users of the same agent

    RLS policy enforces:
        tenant_id = current_setting('app.current_tenant', TRUE)::uuid

    FORCE ROW LEVEL SECURITY ensures even the table owner cannot bypass this.
    """

    __tablename__ = "conversation_embeddings"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid.uuid4,
    )
    tenant_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("tenants.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )
    agent_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        nullable=False,
        index=True,
    )
    user_id: Mapped[str] = mapped_column(
        Text,
        nullable=False,
        comment="Channel-native user identifier (e.g. Slack user ID U12345)",
    )
    content: Mapped[str] = mapped_column(
        Text,
        nullable=False,
        comment="Original message text that was embedded",
    )
    role: Mapped[str] = mapped_column(
        Text,
        nullable=False,
        comment="Message role: 'user' or 'assistant'",
    )
    embedding: Mapped[list[float]] = mapped_column(
        Vector(384),
        nullable=False,
        comment="all-MiniLM-L6-v2 embedding (384 dimensions)",
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        server_default=func.now(),
    )

    def __repr__(self) -> str:
        return (
            f"<ConversationEmbedding id={self.id} "
            f"tenant_id={self.tenant_id} agent_id={self.agent_id} "
            f"user_id={self.user_id!r} role={self.role!r}>"
        )
