# generated by datamodel-codegen:
#   filename:  public-api.yaml
#   timestamp: 2025-12-15T13:54:40+00:00

from __future__ import annotations

from enum import Enum
from typing import Annotated, Any

from pydantic import AnyUrl, AwareDatetime, BaseModel, Field


class ErrorResponse(BaseModel):
    error: str | None = None
    details: dict[str, Any] | None = None


class Type(Enum):
    IMAGE = "image"
    VIDEO = "video"
    GIF = "gif"
    DOCUMENT = "document"


class MediaItem(BaseModel):
    """
    Media referenced in posts. URLs must be publicly reachable over HTTPS by the destination platforms.
    When using third‑party storage, ensure signed links remain valid until upload completes.

    **Uploading Media:**
    - Small files (≤ ~4MB): Use `POST /v1/media` with `multipart/form-data`
    - Large files (> ~4MB, up to 5GB): Use `POST /v1/media` with `Content-Type: application/json` for client-upload flow (presigned URL)
    - See `/v1/media` endpoint documentation for details on both methods

    **Automatic Compression:**
    - Bluesky: images larger than ~1MB are automatically recompressed to meet the platform's blob size limit.
    - Instagram: images >8 MB and videos >100 MB (stories) or >300 MB (reels) are automatically compressed.

    """

    type: Type | None = None
    url: AnyUrl | None = None
    filename: str | None = None
    size: int | None = None
    """
    Optional file size in bytes
    """
    mimeType: str | None = None
    """
    Optional MIME type (e.g. image/jpeg, video/mp4)
    """
    thumbnail: AnyUrl | None = None
    """
    Optional thumbnail image URL for videos
    """
    instagramThumbnail: AnyUrl | None = None
    """
    Optional custom cover image URL for Instagram Reels
    """
    tiktokProcessed: bool | None = None
    """
    Internal flag indicating the image was resized for TikTok
    """


class Status(Enum):
    DRAFT = "draft"
    SCHEDULED = "scheduled"
    PUBLISHING = "publishing"
    PUBLISHED = "published"
    FAILED = "failed"
    PARTIAL = "partial"


class Visibility(Enum):
    PUBLIC = "public"
    PRIVATE = "private"
    UNLISTED = "unlisted"


class ThreadItem(BaseModel):
    content: str | None = None
    mediaItems: list[MediaItem] | None = None


class TwitterPlatformData(BaseModel):
    threadItems: list[ThreadItem] | None = None
    """
    Sequence of tweets in a thread. First item is the root tweet.
    """


class ThreadsPlatformData(BaseModel):
    """
    Constraints:
    - Carousel posts support up to 10 images (no videos in carousels).
    - Single posts support one image or one video.
    - Videos must be H.264/AAC MP4 format, max 5 minutes duration.
    - Images must be JPEG or PNG, max 8 MB each.
    - threadItems creates a reply chain (Threads equivalent of Twitter threads).

    """

    threadItems: list[ThreadItem] | None = None
    """
    Sequence of posts in a Threads thread (root then replies in order).
    """


class ContentType(Enum):
    """
    Set to 'story' to publish as a Facebook Page Story (24-hour ephemeral content). Requires media.
    """

    STORY = "story"


class FacebookPlatformData(BaseModel):
    """
    Constraints:
    - Posts cannot mix videos and images.
    - Multiple images supported via attached_media (up to 10 images for feed posts).
    - Multiple videos in the same post are not supported.
    - Stories require media (single image or video); text captions are not displayed with stories.
    - Stories are ephemeral (disappear after 24 hours).

    """

    contentType: ContentType | None = None
    """
    Set to 'story' to publish as a Facebook Page Story (24-hour ephemeral content). Requires media.
    """
    firstComment: str | None = None
    """
    Optional first comment to post immediately after publishing (feed posts only, not stories)
    """
    pageId: str | None = None
    """
    Target Facebook Page ID. If omitted, uses the selected/default page on the connection.
    """


class ContentType1(Enum):
    """
    Set to 'story' to publish as a Story. Default posts become Reels or feed depending on media.
    """

    STORY = "story"


class UserTag(BaseModel):
    username: Annotated[str, Field(examples=["friend_username"])]
    """
    Instagram username (@ symbol is optional and will be removed automatically)
    """
    x: Annotated[float, Field(examples=[0.5], ge=0.0, le=1.0)]
    """
    X coordinate position from left edge (0.0 = left, 0.5 = center, 1.0 = right)
    """
    y: Annotated[float, Field(examples=[0.5], ge=0.0, le=1.0)]
    """
    Y coordinate position from top edge (0.0 = top, 0.5 = center, 1.0 = bottom)
    """


class InstagramPlatformData(BaseModel):
    """
    Constraints:
    - Feed posts require images with aspect ratio between 0.8 (4:5 portrait) and 1.91 (1.91:1 landscape).
    - Images outside this range (e.g., 9:16 Stories/TikTok format) must use contentType 'story'.
    - Validation happens at post creation; invalid images are rejected immediately with helpful error messages.
    - Carousels support up to 10 media items.
    - Stories require media; no captions are published with Stories.
    - User tags: coordinates range from 0.0 to 1.0 representing position from top-left corner. Tagged users receive notifications.

    **Automatic Compression (similar to Bluesky):**
    - All images (story, post, carousel, thumbnails) exceeding 8 MB are automatically compressed using quality reduction and resizing.
    - Story videos exceeding 100 MB are automatically compressed.
    - Reel videos exceeding 300 MB are automatically compressed.
    - Compression uses Sharp (images) and FFmpeg (videos) to maintain quality while meeting size limits.
    - Original files are preserved; compressed versions are uploaded to blob storage automatically.

    """

    contentType: ContentType1 | None = None
    """
    Set to 'story' to publish as a Story. Default posts become Reels or feed depending on media.
    """
    shareToFeed: bool = True
    """
    For Reels only. When true (default), the Reel appears on both the Reels tab and your main profile feed. Set to false to post to the Reels tab only.
    """
    collaborators: list[str] | None = None
    """
    Up to 3 Instagram usernames to invite as collaborators (feed/Reels only)
    """
    firstComment: str | None = None
    """
    Optional first comment to add after the post is created (not applied to Stories)
    """
    userTags: list[UserTag] | None = None
    """
    Tag Instagram users in photos by username and position coordinates. Only works for single image posts and the first image of carousel posts. Not supported for stories or videos.
    """


class LinkedInPlatformData(BaseModel):
    """
    Constraints:
    - Multi-image posts support up to 20 images.
    - Multi-video posts are not supported.
    - Single PDF document posts are supported.
    - Post ID is returned in the x-restli-id response header.
    - Link previews are automatically generated for URLs when no media is attached (can be disabled with disableLinkPreview).

    """

    firstComment: str | None = None
    """
    Optional first comment to add after the post is created
    """
    disableLinkPreview: bool | None = None
    """
    Set to true to disable automatic link previews for URLs in the post content (default is false)
    """


class PinterestPlatformData(BaseModel):
    title: Annotated[str | None, Field(max_length=100)] = None
    """
    Pin title. Defaults to first line of content or "Pin". Must be ≤ 100 characters.
    """
    boardId: str | None = None
    """
    Target Pinterest board ID. If omitted, the first available board is used.
    """
    link: AnyUrl | None = None
    """
    Destination link (pin URL)
    """
    coverImageUrl: AnyUrl | None = None
    """
    Optional cover image for video pins
    """
    coverImageKeyFrameTime: int | None = None
    """
    Optional key frame time in seconds for derived video cover
    """


class Visibility1(Enum):
    """
    Video visibility setting:
    - public: Anyone can search for and watch (default)
    - unlisted: Only people with the link can watch
    - private: Only you and people you specifically share with can watch

    """

    PUBLIC = "public"
    PRIVATE = "private"
    UNLISTED = "unlisted"


class YouTubePlatformData(BaseModel):
    """
    YouTube video upload settings:
    - Videos ≤ 3 minutes are automatically detected as YouTube Shorts
    - Videos > 3 minutes become regular YouTube videos
    - Custom thumbnails supported for regular videos (via mediaItem.thumbnail)
    - Custom thumbnails NOT supported for Shorts via API
    - Scheduled videos are uploaded immediately as the specified visibility and published at scheduled time
    - Visibility defaults to "public" if not specified

    """

    title: Annotated[str | None, Field(max_length=100)] = None
    """
    Video title. Defaults to first line of content or "Untitled Video". Must be ≤ 100 characters.
    """
    visibility: Visibility1 = "public"
    """
    Video visibility setting:
    - public: Anyone can search for and watch (default)
    - unlisted: Only people with the link can watch
    - private: Only you and people you specifically share with can watch

    """
    firstComment: Annotated[str | None, Field(max_length=10000)] = None
    """
    Optional first comment to post immediately after video upload. Up to 10,000 characters (YouTube's comment limit).
    """


class Type1(Enum):
    """
    Button action type:
    - LEARN_MORE: Link to more information
    - BOOK: Booking/reservation link
    - ORDER: Online ordering link
    - SHOP: E-commerce/shopping link
    - SIGN_UP: Registration/signup link
    - CALL: Phone call action

    """

    LEARN_MORE = "LEARN_MORE"
    BOOK = "BOOK"
    ORDER = "ORDER"
    SHOP = "SHOP"
    SIGN_UP = "SIGN_UP"
    CALL = "CALL"


class CallToAction(BaseModel):
    """
    Optional call-to-action button displayed on the post
    """

    type: Type1
    """
    Button action type:
    - LEARN_MORE: Link to more information
    - BOOK: Booking/reservation link
    - ORDER: Online ordering link
    - SHOP: E-commerce/shopping link
    - SIGN_UP: Registration/signup link
    - CALL: Phone call action

    """
    url: AnyUrl
    """
    Destination URL for the CTA button (required when callToAction is provided)
    """


class GoogleBusinessPlatformData(BaseModel):
    """
    Google Business Profile post settings:
    - Posts support text content and a single image (no videos)
    - Images must be publicly accessible URLs
    - Call-to-action buttons drive user engagement
    - Posts appear on your Google Business Profile and in Google Search/Maps

    """

    callToAction: CallToAction | None = None
    """
    Optional call-to-action button displayed on the post
    """


class CommercialContentType(Enum):
    NONE = "none"
    BRAND_ORGANIC = "brand_organic"
    BRAND_CONTENT = "brand_content"


class MediaType(Enum):
    """
    Optional override. Defaults based on provided media items.
    """

    VIDEO = "video"
    PHOTO = "photo"


class TikTokSettings(BaseModel):
    """
    Required when posting to TikTok. Enforces TikTok Direct Post UX requirements.

    Constraints:
    - Photo carousels support up to 35 images.
    - **Title length limits**:
      - Videos: up to 2200 chars (full content used as title)
      - Photos: content is automatically truncated to 90 chars for title (hashtags/URLs stripped). Use 'description' field for longer text (up to 4000 chars).
    - privacy_level must be chosen from creator_info.privacy_level_options (no defaulting).
    - allow_duet and allow_stitch required for videos; allow_comment for all.
    - content_preview_confirmed and express_consent_given must be true before posting.

    """

    draft: bool | None = None
    """
    When true, Late sends the post to the TikTok Creator Inbox as a draft instead of publishing it immediately. When omitted or false, TikTok uses direct posting (live publish) as usual.

    """
    privacy_level: str | None = None
    """
    One of the values returned by the TikTok creator info API for the account
    """
    allow_comment: bool | None = None
    allow_duet: bool | None = None
    """
    Required for video posts
    """
    allow_stitch: bool | None = None
    """
    Required for video posts
    """
    commercial_content_type: CommercialContentType | None = None
    brand_partner_promote: bool | None = None
    is_brand_organic_post: bool | None = None
    content_preview_confirmed: bool | None = None
    express_consent_given: bool | None = None
    media_type: MediaType | None = None
    """
    Optional override. Defaults based on provided media items.
    """
    video_cover_timestamp_ms: Annotated[int | None, Field(ge=0)] = None
    """
    Optional for video posts. Timestamp in milliseconds to select which frame to use as thumbnail (defaults to 1000ms/1 second).
    """
    photo_cover_index: Annotated[int | None, Field(ge=0)] = None
    """
    Optional for photo carousels. Index of image to use as cover, 0-based (defaults to 0/first image).
    """
    auto_add_music: bool | None = None
    """
    When true, TikTok may add recommended music (photos only)
    """
    video_made_with_ai: bool | None = None
    """
    Set true to disclose AI-generated content
    """
    description: Annotated[str | None, Field(max_length=4000)] = None
    """
    Optional long-form description for photo posts (max 4000 chars).
    Recommended for photo posts when content exceeds 90 characters, as photo titles are automatically truncated to 90 chars (after stripping hashtags/URLs).

    """


class QueueSlot(BaseModel):
    dayOfWeek: Annotated[int | None, Field(ge=0, le=6)] = None
    """
    Day of week (0=Sunday, 6=Saturday)
    """
    time: Annotated[str | None, Field(pattern="^([0-1][0-9]|2[0-3]):[0-5][0-9]$")] = (
        None
    )
    """
    Time in HH:mm format (24-hour)
    """


class QueueSchedule(BaseModel):
    profileId: str | None = None
    """
    Profile ID this queue belongs to
    """
    timezone: str | None = None
    """
    IANA timezone (e.g., America/New_York)
    """
    slots: list[QueueSlot] | None = None
    active: bool | None = None
    """
    Whether the queue is active
    """
    createdAt: AwareDatetime | None = None
    updatedAt: AwareDatetime | None = None


class Pagination(BaseModel):
    page: int | None = None
    limit: int | None = None
    total: int | None = None
    pages: int | None = None


class Profile(BaseModel):
    field_id: Annotated[str | None, Field(alias="_id")] = None
    userId: str | None = None
    name: str | None = None
    description: str | None = None
    color: str | None = None
    isDefault: bool | None = None
    createdAt: AwareDatetime | None = None


class SocialAccount(BaseModel):
    field_id: Annotated[str | None, Field(alias="_id")] = None
    platform: str | None = None
    profileId: str | None = None
    username: str | None = None
    displayName: str | None = None
    isActive: bool | None = None
    followersCount: float | None = None
    """
    Follower count (only included if user has analytics add-on)
    """
    followersLastUpdated: AwareDatetime | None = None
    """
    Last time follower count was updated (only included if user has analytics add-on)
    """


class AccountWithFollowerStats(SocialAccount):
    profilePicture: str | None = None
    currentFollowers: float | None = None
    """
    Current follower count
    """
    lastUpdated: AwareDatetime | None = None
    growth: float | None = None
    """
    Follower change over period
    """
    growthPercentage: float | None = None
    """
    Percentage growth
    """
    dataPoints: float | None = None
    """
    Number of historical snapshots
    """


class ApiKey(BaseModel):
    id: str | None = None
    name: str | None = None
    keyPreview: str | None = None
    expiresAt: AwareDatetime | None = None
    createdAt: AwareDatetime | None = None
    key: str | None = None
    """
    Returned only once, on creation
    """


class BillingPeriod(Enum):
    MONTHLY = "monthly"
    YEARLY = "yearly"


class Limits(BaseModel):
    uploads: int | None = None
    profiles: int | None = None


class Usage(BaseModel):
    uploads: int | None = None
    profiles: int | None = None
    lastReset: AwareDatetime | None = None


class UsageStats(BaseModel):
    planName: str | None = None
    billingPeriod: BillingPeriod | None = None
    signupDate: AwareDatetime | None = None
    limits: Limits | None = None
    usage: Usage | None = None


class Status1(Enum):
    PROCESSING = "processing"
    COMPLETED = "completed"
    FAILED = "failed"


class VideoClip(BaseModel):
    index: Annotated[int | None, Field(examples=[1])] = None
    url: Annotated[
        AnyUrl | None, Field(examples=["https://clips.example.com/clip-1-clean.mp4"])
    ] = None
    """
    Clean version URL (default)
    """
    duration: Annotated[float | None, Field(examples=[58.3])] = None
    """
    Clip duration in seconds
    """
    start_time: Annotated[float | None, Field(examples=[120.5])] = None
    """
    Start time in original video (seconds)
    """
    end_time: Annotated[float | None, Field(examples=[178.8])] = None
    """
    End time in original video (seconds)
    """
    watermarkUrl: Annotated[
        AnyUrl | None,
        Field(examples=["https://clips.example.com/clip-1-watermark.mp4"]),
    ] = None
    """
    Watermarked version URL (free tier)
    """
    cleanUrl: Annotated[
        AnyUrl | None, Field(examples=["https://clips.example.com/clip-1-clean.mp4"])
    ] = None
    """
    Clean version URL (addon users)
    """


class Status2(Enum):
    PROCESSING = "processing"


class VideoClipJobProcessing(BaseModel):
    job_id: Annotated[str | None, Field(examples=["abc123def456"])] = None
    status: Annotated[Status2 | None, Field(examples=["processing"])] = None
    message: Annotated[
        str | None,
        Field(examples=["Video is being processed. Check back in a few minutes."]),
    ] = None


class Status3(Enum):
    COMPLETED = "completed"


class VideoClipJobCompleted(BaseModel):
    job_id: Annotated[str | None, Field(examples=["abc123def456"])] = None
    status: Annotated[Status3 | None, Field(examples=["completed"])] = None
    total_clips: Annotated[int | None, Field(examples=[5])] = None
    clips: list[VideoClip] | None = None


class Status4(Enum):
    FAILED = "failed"


class VideoClipJobFailed(BaseModel):
    job_id: Annotated[str | None, Field(examples=["abc123def456"])] = None
    status: Annotated[Status4 | None, Field(examples=["failed"])] = None
    error: Annotated[
        str | None,
        Field(
            examples=[
                "Video has no audio track. Please use a video that contains both audio and video."
            ]
        ),
    ] = None


class VideoClipUsageStats(BaseModel):
    current: Annotated[int | None, Field(examples=[3])] = None
    """
    Current usage this month
    """
    limit: Annotated[int | None, Field(examples=[5])] = None
    """
    Monthly limit
    """
    remaining: Annotated[int | None, Field(examples=[2])] = None
    """
    Remaining credits this month
    """
    canCreate: Annotated[bool | None, Field(examples=[True])] = None
    """
    Whether user can create new jobs
    """
    hasAddon: Annotated[bool | None, Field(examples=[False])] = None
    """
    Whether user has AI Clipping addon
    """
    message: Annotated[str | None, Field(examples=["Free tier (with watermark)"])] = (
        None
    )


class PostAnalytics(BaseModel):
    impressions: Annotated[int | None, Field(examples=[0])] = None
    reach: Annotated[int | None, Field(examples=[0])] = None
    likes: Annotated[int | None, Field(examples=[0])] = None
    comments: Annotated[int | None, Field(examples=[0])] = None
    shares: Annotated[int | None, Field(examples=[0])] = None
    clicks: Annotated[int | None, Field(examples=[0])] = None
    views: Annotated[int | None, Field(examples=[0])] = None
    engagementRate: Annotated[float | None, Field(examples=[0])] = None
    lastUpdated: AwareDatetime | None = None


class AccountMetrics(BaseModel):
    followers: int | None = None
    """
    Followers/fans count (e.g., Instagram, Facebook Pages, Twitter)
    """
    subscribers: int | None = None
    """
    Subscribers count (e.g., YouTube)
    """
    lastUpdated: AwareDatetime | None = None


class PlatformAnalytics(BaseModel):
    platform: str | None = None
    status: str | None = None
    accountId: str | None = None
    accountUsername: str | None = None
    analytics: PostAnalytics | None = None
    accountMetrics: AccountMetrics | None = None


class AnalyticsOverview(BaseModel):
    totalPosts: int | None = None
    publishedPosts: int | None = None
    scheduledPosts: int | None = None
    lastSync: AwareDatetime | None = None


class AnalyticsSinglePostResponse(BaseModel):
    postId: str | None = None
    status: str | None = None
    content: str | None = None
    scheduledFor: AwareDatetime | None = None
    publishedAt: AwareDatetime | None = None
    analytics: PostAnalytics | None = None
    platformAnalytics: list[PlatformAnalytics] | None = None
    platform: str | None = None
    platformPostUrl: AnyUrl | None = None
    isExternal: bool | None = None


class MediaType1(Enum):
    IMAGE = "image"
    VIDEO = "video"
    GIF = "gif"
    DOCUMENT = "document"


class Post1(BaseModel):
    field_id: Annotated[str | None, Field(alias="_id")] = None
    content: str | None = None
    scheduledFor: AwareDatetime | None = None
    publishedAt: AwareDatetime | None = None
    status: str | None = None
    analytics: PostAnalytics | None = None
    platforms: list[PlatformAnalytics] | None = None
    platform: str | None = None
    platformPostUrl: AnyUrl | None = None
    isExternal: bool | None = None
    thumbnailUrl: AnyUrl | None = None
    mediaType: MediaType1 | None = None
    mediaItems: list[MediaItem] | None = None


class AnalyticsListResponse(BaseModel):
    overview: AnalyticsOverview | None = None
    posts: list[Post1] | None = None
    pagination: Pagination | None = None
    accounts: list[SocialAccount] | None = None
    """
    Connected social accounts (followerCount and followersLastUpdated only included if user has analytics add-on)
    """
    hasAnalyticsAccess: bool | None = None
    """
    Whether user has analytics add-on access
    """


class PostDeleteResponse(BaseModel):
    message: str | None = None


class ProfilesListResponse(BaseModel):
    profiles: list[Profile] | None = None


class ProfileGetResponse(BaseModel):
    profile: Profile | None = None


class ProfileCreateResponse(BaseModel):
    message: str | None = None
    profile: Profile | None = None


class ProfileUpdateResponse(BaseModel):
    message: str | None = None
    profile: Profile | None = None


class ProfileDeleteResponse(BaseModel):
    message: str | None = None


class AccountsListResponse(BaseModel):
    accounts: list[SocialAccount] | None = None
    hasAnalyticsAccess: bool | None = None
    """
    Whether user has analytics add-on access
    """


class AccountGetResponse(BaseModel):
    account: SocialAccount | None = None


class DateRange(BaseModel):
    from_: Annotated[AwareDatetime | None, Field(alias="from")] = None
    to: AwareDatetime | None = None


class Aggregation(Enum):
    DAILY = "daily"
    WEEKLY = "weekly"
    MONTHLY = "monthly"


class FollowerStatsResponse(BaseModel):
    accounts: list[AccountWithFollowerStats] | None = None
    dateRange: DateRange | None = None
    aggregation: Aggregation | None = None


class Type2(Enum):
    IMAGE = "image"
    VIDEO = "video"
    DOCUMENT = "document"


class UploadedFile(BaseModel):
    type: Type2 | None = None
    url: AnyUrl | None = None
    filename: str | None = None
    size: int | None = None
    mimeType: str | None = None


class MediaUploadResponse(BaseModel):
    files: list[UploadedFile] | None = None


class Status5(Enum):
    PENDING = "pending"
    COMPLETED = "completed"
    EXPIRED = "expired"


class UploadTokenResponse(BaseModel):
    token: str | None = None
    uploadUrl: AnyUrl | None = None
    expiresAt: AwareDatetime | None = None
    status: Status5 | None = None


class UploadTokenStatusResponse(BaseModel):
    token: str | None = None
    status: Status5 | None = None
    files: list[UploadedFile] | None = None
    createdAt: AwareDatetime | None = None
    expiresAt: AwareDatetime | None = None
    completedAt: AwareDatetime | None = None


class QueueSlotsResponse(BaseModel):
    exists: bool | None = None
    schedule: QueueSchedule | None = None
    nextSlots: list[AwareDatetime] | None = None


class QueueUpdateResponse(BaseModel):
    success: bool | None = None
    schedule: QueueSchedule | None = None
    nextSlots: list[AwareDatetime] | None = None
    reshuffledCount: int | None = None


class QueueDeleteResponse(BaseModel):
    success: bool | None = None
    deleted: bool | None = None


class QueuePreviewResponse(BaseModel):
    profileId: str | None = None
    count: int | None = None
    slots: list[AwareDatetime] | None = None


class QueueNextSlotResponse(BaseModel):
    profileId: str | None = None
    nextSlot: AwareDatetime | None = None
    timezone: str | None = None


class DownloadFormat(BaseModel):
    formatId: str | None = None
    ext: str | None = None
    resolution: str | None = None
    filesize: int | None = None
    quality: str | None = None


class DownloadResponse(BaseModel):
    url: AnyUrl | None = None
    title: str | None = None
    thumbnail: AnyUrl | None = None
    duration: int | None = None
    formats: list[DownloadFormat] | None = None


class TranscriptSegment(BaseModel):
    text: str | None = None
    start: float | None = None
    duration: float | None = None


class TranscriptResponse(BaseModel):
    transcript: str | None = None
    segments: list[TranscriptSegment] | None = None
    language: str | None = None


class Status7(Enum):
    SAFE = "safe"
    BANNED = "banned"
    RESTRICTED = "restricted"
    UNKNOWN = "unknown"


class HashtagInfo(BaseModel):
    hashtag: str | None = None
    status: Status7 | None = None
    postCount: int | None = None


class HashtagCheckResponse(BaseModel):
    hashtags: list[HashtagInfo] | None = None


class CaptionResponse(BaseModel):
    caption: str | None = None


class User(BaseModel):
    field_id: Annotated[str | None, Field(alias="_id")] = None
    email: str | None = None
    name: str | None = None
    role: str | None = None
    createdAt: AwareDatetime | None = None


class UsersListResponse(BaseModel):
    users: list[User] | None = None


class UserGetResponse(BaseModel):
    user: User | None = None


class TikTokPlatformData(BaseModel):
    """
    TikTok platform-specific settings. Contains tiktokSettings for video/photo posting options.

    """

    tiktokSettings: TikTokSettings | None = None


class VideoClipJob(BaseModel):
    field_id: Annotated[
        str | None, Field(alias="_id", examples=["507f1f77bcf86cd799439011"])
    ] = None
    jobId: Annotated[str | None, Field(examples=["abc123def456"])] = None
    videoUrl: Annotated[
        AnyUrl | None, Field(examples=["https://storage.example.com/video.mp4"])
    ] = None
    videoFileName: Annotated[str | None, Field(examples=["my-video.mp4"])] = None
    status: Annotated[Status1 | None, Field(examples=["completed"])] = None
    clips: list[VideoClip] | None = None
    totalClips: Annotated[int | None, Field(examples=[5])] = None
    error: Annotated[str | None, Field(examples=[None])] = None
    createdAt: Annotated[
        AwareDatetime | None, Field(examples=["2025-10-22T10:30:00Z"])
    ] = None
    completedAt: Annotated[
        AwareDatetime | None, Field(examples=["2025-10-22T10:45:00Z"])
    ] = None


class PlatformTarget(BaseModel):
    platform: Annotated[str | None, Field(examples=["twitter"])] = None
    """
    Supported values: twitter, threads, instagram, youtube, facebook, linkedin, pinterest, reddit, tiktok, bluesky, googlebusiness
    """
    accountId: str | None = None
    customContent: str | None = None
    customMedia: list[MediaItem] | None = None
    scheduledFor: AwareDatetime | None = None
    """
    Optional per-platform scheduled time override (uses post.scheduledFor when omitted)
    """
    platformSpecificData: (
        TwitterPlatformData
        | ThreadsPlatformData
        | FacebookPlatformData
        | InstagramPlatformData
        | LinkedInPlatformData
        | PinterestPlatformData
        | YouTubePlatformData
        | GoogleBusinessPlatformData
        | TikTokPlatformData
        | None
    ) = None
    """
    Platform-specific overrides and options.
    """
    status: Annotated[str | None, Field(examples=["pending"])] = None
    """
    Platform-specific status: pending, publishing, published, failed
    """
    platformPostId: Annotated[str | None, Field(examples=["1234567890123456789"])] = (
        None
    )
    """
    The native post ID on the platform (populated after successful publish)
    """
    platformPostUrl: Annotated[
        AnyUrl | None,
        Field(examples=["https://twitter.com/acmecorp/status/1234567890123456789"]),
    ] = None
    """
    Public URL of the published post on the platform.
    Populated after successful publish. For immediate posts (publishNow=true),
    this is included in the response. For scheduled posts, fetch the post
    via GET /v1/posts/{postId} after the scheduled time.

    """
    publishedAt: AwareDatetime | None = None
    """
    Timestamp when the post was published to this platform
    """


class Post(BaseModel):
    field_id: Annotated[str | None, Field(alias="_id")] = None
    userId: str | None = None
    title: str | None = None
    """
    YouTube: title must be ≤ 100 characters.

    """
    content: str | None = None
    mediaItems: list[MediaItem] | None = None
    platforms: list[PlatformTarget] | None = None
    scheduledFor: AwareDatetime | None = None
    timezone: str | None = None
    status: Status | None = None
    tags: list[str] | None = None
    """
    YouTube tag constraints when targeting YouTube:
    - No count cap; duplicates removed.
    - Each tag must be ≤ 100 chars.
    - Combined characters across all tags ≤ 500.

    """
    hashtags: list[str] | None = None
    mentions: list[str] | None = None
    visibility: Visibility | None = None
    metadata: dict[str, Any] | None = None
    queuedFromProfile: str | None = None
    """
    Profile ID if the post was scheduled via the queue
    """
    createdAt: AwareDatetime | None = None
    updatedAt: AwareDatetime | None = None


class PostsListResponse(BaseModel):
    posts: list[Post] | None = None
    pagination: Pagination | None = None


class PostGetResponse(BaseModel):
    post: Post | None = None


class PostCreateResponse(BaseModel):
    message: str | None = None
    post: Post | None = None


class PostUpdateResponse(BaseModel):
    message: str | None = None
    post: Post | None = None


class PostRetryResponse(BaseModel):
    message: str | None = None
    post: Post | None = None
