# FILE: src/apps/scheduling/models/scheduling_activity_log.py
from __future__ import annotations

from typing import Optional
from uuid import UUID

from sqlalchemy import ForeignKey, Index, String, Text, text
from sqlalchemy.dialects.postgresql import JSONB, UUID as PG_UUID
from sqlalchemy.orm import Mapped, mapped_column

from src.database.base import TenantModel


class SchedulingActivityLog(TenantModel):
    """Append-only audit trail for every state change on a service (INDL-34).

    Rows are INSERT-only by design. A DB-level REVOKE of UPDATE/DELETE on this
    table (SAC-10 / A08) is enforced at the ops/role level, not in this migration.

    The ``metadata`` column collides with SQLAlchemy's Declarative
    ``MetaData`` attribute, so the Python attribute is named ``log_metadata``
    and explicitly mapped to the ``metadata`` column. It is built internally by
    ``SchedulingService.log_event()`` from a trusted allow-list of keys only and
    is NEVER returned to API clients (see ``ActivityLogEntrySchema``).

    ``actor_id`` is nullable (migration 0059) — the INDL-38 family-notification
    ARQ jobs write ``confirmation_email_sent`` / ``reminder_email_sent`` /
    ``email_error`` entries with no human actor.
    """

    __tablename__ = "scheduling_activity_log"

    # Migration 0057 owns the DDL; this mirrors it (service_id, created_at DESC)
    # so `alembic revision --autogenerate` doesn't churn on an index mismatch.
    __table_args__ = (
        Index(
            "idx_scheduling_activity_service",
            "service_id",
            text("created_at DESC"),
        ),
    )

    tenant_id: Mapped[UUID] = mapped_column(
        PG_UUID(as_uuid=True),
        ForeignKey("accounts.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )

    service_id: Mapped[UUID] = mapped_column(
        PG_UUID(as_uuid=True),
        ForeignKey("services.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )

    actor_id: Mapped[Optional[UUID]] = mapped_column(
        PG_UUID(as_uuid=True),
        ForeignKey("users.id"),
        nullable=True,
    )

    event_type: Mapped[str] = mapped_column(String(50), nullable=False)
    from_status: Mapped[Optional[str]] = mapped_column(String(30), nullable=True)
    to_status: Mapped[Optional[str]] = mapped_column(String(30), nullable=True)
    description: Mapped[str] = mapped_column(Text, nullable=False)

    # Python attr `log_metadata` -> DB column `metadata` (avoids the Declarative clash).
    log_metadata: Mapped[Optional[dict]] = mapped_column("metadata", JSONB, nullable=True)
