"""Semantic-search embedding table (NEW in v2 — not carried from v1).

Requires the ``vector`` PG extension (pgvector). One embedding row per
(source row, model); ``content_hash`` lets the indexer skip unchanged content.
"""
from __future__ import annotations

from datetime import datetime
from typing import Any

from pgvector.sqlalchemy import Vector
from sqlalchemy import (
    BigInteger,
    CheckConstraint,
    Index,
    Text,
    UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column

from .base import Base, created_at_column, garden_fk, pk_column


class Embedding(Base):
    """A 768-dim vector for one embeddable source row.

    ``source_type`` vocabulary (enforced by CHECK, no native PG enum):
    'note', 'field_note', 'chat_message'. ``source_id`` is a soft reference
    into the corresponding table (no FK — sources live in different tables).
    """

    __tablename__ = "embeddings"
    __table_args__ = (
        CheckConstraint(
            "source_type IN ('note', 'field_note', 'chat_message')",
            name="source_type",
        ),
        UniqueConstraint("source_type", "source_id", "model"),
        Index(
            "ix_embeddings_embedding_hnsw",
            "embedding",
            postgresql_using="hnsw",
            postgresql_ops={"embedding": "vector_cosine_ops"},
        ),
    )

    id: Mapped[int] = pk_column()
    garden_id: Mapped[int] = garden_fk()
    source_type: Mapped[str] = mapped_column(Text, nullable=False)
    source_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
    model: Mapped[str] = mapped_column(Text, nullable=False)
    content_hash: Mapped[str] = mapped_column(Text, nullable=False)
    embedding: Mapped[Any] = mapped_column(Vector(768), nullable=False)
    created_at: Mapped[datetime] = created_at_column()
