from __future__ import annotations from datetime import UTC, datetime from uuid import uuid4 from sqlalchemy import ( BigInteger, Boolean, DateTime, ForeignKey, Index, Integer, String, Text, UniqueConstraint, ) from sqlalchemy.orm import Mapped, mapped_column, relationship from app.db.base import Base class Enterprise(Base): __tablename__ = "enterprises" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) name: Mapped[str] = mapped_column(String(255), nullable=False) slug: Mapped[str] = mapped_column(String(64), nullable=False, unique=True, index=True) status: Mapped[str] = mapped_column(String(16), nullable=False, default="active", index=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC), ) members: Mapped[list["EnterpriseMember"]] = relationship(back_populates="enterprise", cascade="all, delete-orphan") farm_hubs: Mapped[list["FarmHub"]] = relationship(back_populates="enterprise", cascade="all, delete-orphan") class EnterpriseMember(Base): __tablename__ = "enterprise_members" __table_args__ = (UniqueConstraint("user_id", "enterprise_id", name="uq_enterprise_members_user_enterprise"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) user_id: Mapped[str] = mapped_column(String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) role: Mapped[str] = mapped_column(String(32), nullable=False, default="viewer") created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) enterprise: Mapped[Enterprise] = relationship(back_populates="members") class FarmHub(Base): __tablename__ = "farm_hubs" __table_args__ = (UniqueConstraint("hub_site_id", name="uq_farm_hubs_hub_site_id"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) name: Mapped[str] = mapped_column(String(255), nullable=False) hub_site_id: Mapped[str] = mapped_column(String(36), nullable=False) url: Mapped[str | None] = mapped_column(String(512), nullable=True) status: Mapped[str] = mapped_column(String(16), nullable=False, default="pending", index=True) last_seen: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) wesp_version: Mapped[str | None] = mapped_column(String(64), nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC), ) enterprise: Mapped[Enterprise] = relationship(back_populates="farm_hubs") credentials: Mapped[list["HubCredential"]] = relationship(back_populates="farm_hub", cascade="all, delete-orphan") farm_access: Mapped[list["UserFarmAccess"]] = relationship(back_populates="farm_hub", cascade="all, delete-orphan") class UserFarmAccess(Base): __tablename__ = "user_farm_access" __table_args__ = (UniqueConstraint("user_id", "farm_hub_id", name="uq_user_farm_access_user_farm"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) user_id: Mapped[str] = mapped_column(String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) farm_hub_id: Mapped[str] = mapped_column( String(36), ForeignKey("farm_hubs.id", ondelete="CASCADE"), nullable=False, index=True ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) farm_hub: Mapped[FarmHub] = relationship(back_populates="farm_access") class HubCredential(Base): __tablename__ = "hub_credentials" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) farm_hub_id: Mapped[str] = mapped_column( String(36), ForeignKey("farm_hubs.id", ondelete="CASCADE"), nullable=False, index=True ) secret_hash: Mapped[str] = mapped_column(String(255), nullable=False) paired_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) farm_hub: Mapped[FarmHub] = relationship(back_populates="credentials") class HubPairingSession(Base): __tablename__ = "hub_pairing_sessions" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) code: Mapped[str] = mapped_column(String(6), nullable=False, index=True) code_hash: Mapped[str] = mapped_column(String(64), nullable=False) expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) confirmed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) farm_hub_id: Mapped[str | None] = mapped_column(String(36), ForeignKey("farm_hubs.id", ondelete="SET NULL"), nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) class SyncOutbox(Base): __tablename__ = "sync_outbox" __table_args__ = ( Index("idx_sync_outbox_enterprise_status", "enterprise_id", "status"), Index("idx_sync_outbox_table_record", "table_name", "record_id"), ) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) event_id: Mapped[str] = mapped_column(String(36), nullable=False, unique=True) origin: Mapped[str] = mapped_column(String(32), nullable=False) origin_site_id: Mapped[str | None] = mapped_column(String(36), nullable=True) seq: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True) domain: Mapped[str] = mapped_column(String(16), nullable=False, default="global") table_name: Mapped[str] = mapped_column(String(64), nullable=False) record_id: Mapped[str] = mapped_column(String(128), nullable=False) action: Mapped[str] = mapped_column(String(16), nullable=False) version: Mapped[int] = mapped_column(Integer, nullable=False, default=1) content_hash: Mapped[str] = mapped_column(String(64), nullable=False, default="") payload_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") status: Mapped[str] = mapped_column(String(16), nullable=False, default="pending", index=True) emitted_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) class SyncEventLog(Base): __tablename__ = "sync_event_log" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) event_id: Mapped[str] = mapped_column(String(36), nullable=False, unique=True) origin: Mapped[str] = mapped_column(String(32), nullable=False) origin_site_id: Mapped[str | None] = mapped_column(String(36), nullable=True) seq: Mapped[int] = mapped_column(BigInteger, nullable=False) domain: Mapped[str] = mapped_column(String(16), nullable=False, default="global") table_name: Mapped[str] = mapped_column(String(64), nullable=False) record_id: Mapped[str] = mapped_column(String(128), nullable=False) action: Mapped[str] = mapped_column(String(16), nullable=False) version: Mapped[int] = mapped_column(Integer, nullable=False, default=1) content_hash: Mapped[str] = mapped_column(String(64), nullable=False, default="") payload_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") received_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) class SyncAppliedEvent(Base): __tablename__ = "sync_applied_events" __table_args__ = (UniqueConstraint("site_id", "event_id", name="uq_sync_applied_events_site_event"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) site_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) event_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) applied_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) class SyncCursor(Base): __tablename__ = "sync_cursors" __table_args__ = (UniqueConstraint("farm_hub_id", "direction", name="uq_sync_cursors_hub_direction"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) farm_hub_id: Mapped[str] = mapped_column( String(36), ForeignKey("farm_hubs.id", ondelete="CASCADE"), nullable=False, index=True ) direction: Mapped[str] = mapped_column(String(16), nullable=False) last_acked_seq: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) last_pulled_seq: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC), ) class SyncRecordState(Base): __tablename__ = "sync_record_state" __table_args__ = ( UniqueConstraint("enterprise_id", "table_name", "record_id", name="uq_sync_record_state_ent_table_record"), ) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) table_name: Mapped[str] = mapped_column(String(64), nullable=False) record_id: Mapped[str] = mapped_column(String(128), nullable=False) agreed_version: Mapped[int] = mapped_column(Integer, nullable=False, default=1) agreed_hash: Mapped[str] = mapped_column(String(64), nullable=False, default="") last_event_id: Mapped[str | None] = mapped_column(String(36), nullable=True) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC), ) class SyncConflict(Base): __tablename__ = "sync_conflicts" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) table_name: Mapped[str] = mapped_column(String(64), nullable=False) record_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True) farm_hub_id: Mapped[str | None] = mapped_column(String(36), ForeignKey("farm_hubs.id", ondelete="SET NULL"), nullable=True) orchestrator_snapshot_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") hub_snapshot_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") held_event_ids_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]") status: Mapped[str] = mapped_column(String(16), nullable=False, default="pending", index=True) resolution: Mapped[str | None] = mapped_column(String(32), nullable=True) resolved_by: Mapped[str | None] = mapped_column(String(36), nullable=True) resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) class SyncReconcileRun(Base): __tablename__ = "sync_reconcile_runs" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) started_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) mismatches_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0) auto_repaired: Mapped[int] = mapped_column(Integer, nullable=False, default=0) status: Mapped[str] = mapped_column(String(16), nullable=False, default="running") class ReportSyncState(Base): __tablename__ = "report_sync_state" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) farm_hub_id: Mapped[str] = mapped_column( String(36), ForeignKey("farm_hubs.id", ondelete="CASCADE"), nullable=False, unique=True ) enterprise_id: Mapped[str] = mapped_column( String(36), ForeignKey("enterprises.id", ondelete="CASCADE"), nullable=False, index=True ) last_report_cursor: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0) last_pull_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)