import uuid from datetime import datetime, timezone from sqlalchemy import DateTime, ForeignKey, Integer, Text, UniqueConstraint from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.orm import Mapped, mapped_column from ..database import Base class AdventureEntity(Base): __tablename__ = "choose_your_own_adventure" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True ) status: Mapped[str] = mapped_column(Text, nullable=False, default="awaiting_first_entry") language: Mapped[str] = mapped_column(Text, nullable=False) source_language: Mapped[str] = mapped_column(Text, nullable=False) competencies: Mapped[list] = mapped_column(JSONB, nullable=False, default=list) max_entry_count: Mapped[int] = mapped_column(Integer, nullable=False, default=6) entry_story_text_target_length: Mapped[dict] = mapped_column( JSONB, nullable=False, default=lambda: {"min": 700, "max": 800} ) title: Mapped[str] = mapped_column(Text, nullable=False, default="Untitled adventure") description: Mapped[str | None] = mapped_column(Text, nullable=True) plot_summary: Mapped[str | None] = mapped_column(Text, nullable=True) genres: Mapped[list] = mapped_column(JSONB, nullable=False, default=list) setting: Mapped[list] = mapped_column(JSONB, nullable=False, default=list) vibes: Mapped[list] = mapped_column(JSONB, nullable=False, default=list) protagonist: Mapped[list] = mapped_column(JSONB, nullable=False, default=list) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc) ) deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) class AdventureEntryEntity(Base): __tablename__ = "choose_your_own_adventure_entry" __table_args__ = ( UniqueConstraint("adventure_id", "entry_index", name="uq_cyoa_entry_adventure_index"), ) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) adventure_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("choose_your_own_adventure.id", ondelete="CASCADE"), nullable=False, index=True, ) generated_from_choice_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey( "choose_your_own_adventure_entry_possible_choice.id", ondelete="SET NULL" ), nullable=True, ) status: Mapped[str] = mapped_column(Text, nullable=False, default="generating") entry_index: Mapped[int] = mapped_column(Integer, nullable=False) story_text: Mapped[str | None] = mapped_column(Text, nullable=True) gamemaster_notes: Mapped[str | None] = mapped_column(Text, nullable=True) llm_data: Mapped[dict | None] = mapped_column(JSONB, nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc) ) class AdventureEntryPossibleChoiceEntity(Base): __tablename__ = "choose_your_own_adventure_entry_possible_choice" __table_args__ = ( UniqueConstraint("entry_id", "index", name="uq_cyoa_choice_entry_index"), ) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) entry_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("choose_your_own_adventure_entry.id", ondelete="CASCADE"), nullable=False, index=True, ) index: Mapped[int] = mapped_column(Integer, nullable=False) label: Mapped[str] = mapped_column(Text, nullable=False) text: Mapped[str] = mapped_column(Text, nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc) ) class AdventureEntryPossibleChoiceDecisionEntity(Base): __tablename__ = "choose_your_own_adventure_entry_possible_choice_decision" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) choice_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey( "choose_your_own_adventure_entry_possible_choice.id", ondelete="CASCADE" ), nullable=False, index=True, ) user_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc) ) class AdventureEntryTranslationEntity(Base): __tablename__ = "choose_your_own_adventure_entry_translation" __table_args__ = ( UniqueConstraint( "entry_id", "component_type", "target_language", name="uq_cyoa_translation_entry_component_lang", ), ) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) entry_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("choose_your_own_adventure_entry.id", ondelete="CASCADE"), nullable=False, index=True, ) component_type: Mapped[str] = mapped_column(Text, nullable=False, default="story_text") target_language: Mapped[str] = mapped_column(Text, nullable=False) translated_text: Mapped[str] = mapped_column(Text, nullable=False) class AdventureEntryAudioEntity(Base): __tablename__ = "choose_your_own_adventure_entry_audio" __table_args__ = ( UniqueConstraint("entry_id", "component_type", name="uq_cyoa_audio_entry_component"), ) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) entry_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("choose_your_own_adventure_entry.id", ondelete="CASCADE"), nullable=False, index=True, ) component_type: Mapped[str] = mapped_column(Text, nullable=False, default="story_text") tts_provider: Mapped[str] = mapped_column(Text, nullable=False, default="google_gemini") tts_options: Mapped[dict | None] = mapped_column(JSONB, nullable=True) file_name: Mapped[str] = mapped_column(Text, nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc) )