from sqlalchemy import Index, Integer, Text, text
from sqlalchemy.orm import Mapped, mapped_column

from scribe.models import Base
from scribe.models.base import SoftDeleteMixin, TimestampMixin, iso


class CanonicalSystem(Base, TimestampMixin, SoftDeleteMixin):
    """A GLOBAL area name — the shared vocabulary every project's Systems
    can point at (milestone 307, decision note 3026).

    A `System` is per-project and NOT NULL on project_id, so nothing outside a
    project can reference one: a rule that applies across projects has no way
    to say "this is about CI" without chaining itself to one project's row.
    This table is that join key. It carries no `user_id` on purpose — a shared
    project must INHERIT the vocabulary rather than re-earn it, so the catalog
    is global and the same word means the same thing in every install.

    It is a convergence aid, never a gate: `systems.canonical_id` is nullable,
    an unmapped System stays fully usable, and `record_systems` never sees this
    table at all — the local name is a legitimate local label and is never
    rewritten to match.

    `slug` is the match key, not a display value. It folds the spelling
    differences that produced four names for one area on the author's own
    instance ("CI & Release" / "CI and Release" / "CI & release"): an exact slug
    hit maps automatically, and anything short of that becomes a proposal for a
    human to confirm. See services/canonical_systems.canonical_slug.
    """

    __tablename__ = "canonical_systems"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(Text, nullable=False)
    # Normalized match key — unique among LIVE rows, so a soft-deleted entry
    # doesn't block recreating the same area (the partial-unique convention
    # rules/topics already use).
    slug: Mapped[str] = mapped_column(Text, nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    order_index: Mapped[int] = mapped_column(Integer, default=0, server_default="0")

    __table_args__ = (
        Index(
            "uq_canonical_systems_slug", "slug",
            unique=True, postgresql_where=text("deleted_at IS NULL"),
        ),
    )

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "name": self.name,
            "slug": self.slug,
            "description": self.description,
            "order_index": self.order_index,
            "created_at": iso(self.created_at),
            "updated_at": iso(self.updated_at),
        }
