"""Localization & media-ref DTOs — Phase 11.5.""" from __future__ import annotations from datetime import datetime from uuid import UUID from pydantic import BaseModel, ConfigDict, Field from app.models.types import ( LocalizationStatus, LocalizationTarget, MediaKind, MediaRefStatus, TextDirection, ) from app.schemas.common import ORMBase _FORBID = ConfigDict(extra="forbid") class SiteLocaleBindingCreate(BaseModel): model_config = _FORBID workspace_id: UUID site_id: UUID locale_profile_id: UUID text_direction: TextDirection | None = None is_default: bool = False is_active: bool = True sort_order: int = 0 metadata_json: dict | None = None class SiteLocaleBindingUpdate(BaseModel): model_config = _FORBID text_direction: TextDirection | None = None is_default: bool | None = None is_active: bool | None = None sort_order: int | None = None metadata_json: dict | None = None version: int = Field(ge=1) class SiteLocaleBindingRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID site_id: UUID locale_profile_id: UUID locale_code: str text_direction: TextDirection is_default: bool is_active: bool sort_order: int metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class SiteLocaleBindingListResponse(BaseModel): items: list[SiteLocaleBindingRead] total: int page: int page_size: int class ExperienceLocalizationUpsert(BaseModel): model_config = _FORBID workspace_id: UUID target_type: LocalizationTarget target_id: UUID locale: str = Field(max_length=16) text_direction: TextDirection = TextDirection.RTL title: str | None = Field(default=None, max_length=255) summary: str | None = None content_json: dict | None = None status: LocalizationStatus = LocalizationStatus.DRAFT metadata_json: dict | None = None version: int | None = Field(default=None, ge=1) class ExperienceLocalizationUpdate(BaseModel): model_config = _FORBID text_direction: TextDirection | None = None title: str | None = Field(default=None, max_length=255) summary: str | None = None content_json: dict | None = None status: LocalizationStatus | None = None metadata_json: dict | None = None version: int = Field(ge=1) class ExperienceLocalizationRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID target_type: LocalizationTarget target_id: UUID locale: str text_direction: TextDirection title: str | None summary: str | None content_json: dict | None status: LocalizationStatus metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class ExperienceLocalizationListResponse(BaseModel): items: list[ExperienceLocalizationRead] total: int page: int page_size: int class ExperienceMediaRefCreate(BaseModel): model_config = _FORBID workspace_id: UUID site_id: UUID | None = None page_id: UUID | None = None owner_type: str | None = Field(default=None, max_length=50) owner_id: UUID | None = None kind: MediaKind = MediaKind.IMAGE storage_file_ref: str = Field(max_length=255) alt_text: str | None = Field(default=None, max_length=255) caption: str | None = Field(default=None, max_length=500) locale: str | None = Field(default=None, max_length=16) text_direction: TextDirection | None = None sort_order: int = 0 status: MediaRefStatus = MediaRefStatus.ACTIVE metadata_json: dict | None = None class ExperienceMediaRefUpdate(BaseModel): model_config = _FORBID site_id: UUID | None = None page_id: UUID | None = None owner_type: str | None = Field(default=None, max_length=50) owner_id: UUID | None = None kind: MediaKind | None = None storage_file_ref: str | None = Field(default=None, max_length=255) alt_text: str | None = Field(default=None, max_length=255) caption: str | None = Field(default=None, max_length=500) locale: str | None = Field(default=None, max_length=16) text_direction: TextDirection | None = None sort_order: int | None = None status: MediaRefStatus | None = None metadata_json: dict | None = None version: int = Field(ge=1) class ExperienceMediaRefRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID site_id: UUID | None page_id: UUID | None owner_type: str | None owner_id: UUID | None kind: MediaKind storage_file_ref: str alt_text: str | None caption: str | None locale: str | None text_direction: TextDirection | None sort_order: int status: MediaRefStatus metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class ExperienceMediaRefListResponse(BaseModel): items: list[ExperienceMediaRefRead] total: int page: int page_size: int