"""audit_log — the unified audit/undo table (04-architecture "Audit").

Every state-changing action writes (actor, impersonated_by, action,
entity, before/after image). For BULK operations the before-image is
COMPLETE — judgment #11's undo is implemented as replay-from-audit-row,
one mechanism, not an audit log plus a separate undo log.

M2 ships the table; services/audit.py + writers land with the first
mutating features (M5 bulk safety). The migration transforms do NOT
write here — their record is the migration_runs report table.
"""

import uuid
from datetime import datetime

from sqlalchemy import DateTime, ForeignKey, Index, Text, Uuid, func
from sqlalchemy.orm import Mapped, mapped_column

from app.models.base import Base, PortableJSON


class AuditLog(Base):
    __tablename__ = "audit_log"
    __table_args__ = (
        Index("ix_audit_log_tenant_created", "tenant_id", "created_at"),
        Index("ix_audit_log_entity", "entity_type", "entity_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid(), primary_key=True, default=uuid.uuid4)
    tenant_id: Mapped[uuid.UUID | None] = mapped_column(ForeignKey("tenants.id"))
    actor_user_id: Mapped[uuid.UUID | None] = mapped_column(
        ForeignKey("users.id", ondelete="SET NULL")
    )
    # set when view-as is active (app-layer impersonation, judgment #7)
    impersonated_by: Mapped[uuid.UUID | None] = mapped_column(
        ForeignKey("users.id", ondelete="SET NULL")
    )
    action: Mapped[str] = mapped_column(Text())
    entity_type: Mapped[str | None] = mapped_column(Text())
    entity_id: Mapped[uuid.UUID | None] = mapped_column(Uuid())
    # full before-image (COMPLETE for bulk ops — the undo payload)
    before: Mapped[dict | None] = mapped_column(PortableJSON, nullable=True)
    after: Mapped[dict | None] = mapped_column(PortableJSON, nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now()
    )
