"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.closeFriends = exports.privacySettings = exports.userSocialLinks = exports.SOCIAL_PLATFORMS = exports.userGalleryImages = exports.userPresence = exports.videoRecommendations = exports.pokes = exports.userBlocks = exports.friendships = exports.FRIENDSHIP_STATUS = exports.adClicks = exports.adImpressions = exports.ads = exports.playlistViews = exports.featuredPlaylists = exports.playlistVideos = exports.playlists = exports.contentReports = exports.REPORT_STATUS = exports.REPORT_TYPES = exports.moderationWordLists = exports.WORD_FILTER_LEVELS = exports.rateLimits = exports.appSettings = exports.chatThreadReadStatus = exports.userDailyActivity = exports.highlightCooldowns = exports.videoReactions = exports.REACTION_TYPES = exports.userFinishes = exports.userStats = exports.userAchievements = exports.emailChangeTokens = exports.passwordResetTokens = exports.emailVerificationTokens = exports.commentModeration = exports.sessionBans = exports.authTokens = exports.mediaUsers = exports.v2Users = exports.views = exports.comments = exports.upvotes = exports.sessions = exports.publicMedia = exports.jobs = exports.compilations = exports.videos = exports.DIRECTORY_TYPES = void 0;
exports.PIPELINE_STEP_STATUS = exports.PIPELINE_STATUS = exports.performerDiscrepancies = exports.DISCREPANCY_RESOLUTIONS = exports.DISCREPANCY_STATUS = exports.DISCREPANCY_TYPES = exports.performerFaces = exports.FACE_STATUS = exports.creators = exports.tagGenerationJobs = exports.watchPartyInvites = exports.INVITE_STATUS = exports.watchPartyReactions = exports.watchPartyChatMessages = exports.watchPartyParticipants = exports.watchPartySessions = exports.LOOP_MODE = exports.WATCH_PARTY_STATUS = exports.digestClipTags = exports.digestSuggestedTags = exports.SUGGESTED_TAG_STATUS = exports.videoTags = exports.videoSegments = exports.videoTagTimeline = exports.VOCAL_CATEGORIES = exports.SEGMENT_TYPES = exports.videoSceneCuts = exports.digestGeneratedScenes = exports.digestOutputFolders = exports.digestCompilations = exports.CAPTION_SIZES = exports.CAPTION_POSITIONS = exports.digestGeneratedClips = exports.digestSelectedClips = exports.CLIP_SOURCES = exports.CLIP_STATUS = exports.CLIP_TYPES = exports.digestVideoTags = exports.videoDigests = exports.DIGEST_STATUS = exports.publicMediaPerformers = exports.userTagPreferences = exports.userUploadSuggestedTags = exports.publicMediaTags = exports.tags = exports.tagCategories = exports.uploadInvites = exports.UPLOAD_INVITE_STATUS = exports.userUploads = exports.USER_UPLOAD_STATUS = void 0;
exports.videoOcrResults = exports.OCR_TEXT_TYPES = exports.publishedInboxFiles = exports.INBOX_FILE_TYPES = exports.geoBlockingRules = exports.GEO_BLOCKING_MODES = exports.notificationPreferences = exports.notifications = exports.NOTIFICATION_TYPES = exports.paymentAuditLog = exports.payments = exports.invoices = exports.userSubscriptions = exports.subscriptionPlans = exports.pipelineTemplates = exports.resourceSnapshots = exports.pipelineStepEvents = exports.pipelineSteps = exports.pipelines = void 0;
const pg_core_1 = require("drizzle-orm/pg-core");
// Directory type enum for efficient filtering (replaces LIKE patterns)
exports.DIRECTORY_TYPES = ['studios', 'gifs', 'private', 'inbox', 'curated', 'playback', 'compilations', 'videos', 'highlights'];
exports.videos = (0, pg_core_1.pgTable)('videos', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    path: (0, pg_core_1.text)('path').notNull().unique(),
    filename: (0, pg_core_1.text)('filename').notNull(),
    producer: (0, pg_core_1.text)('producer'),
    creator: (0, pg_core_1.text)('creator'),
    title: (0, pg_core_1.text)('title'),
    durationSeconds: (0, pg_core_1.integer)('duration_seconds'),
    quality: (0, pg_core_1.text)('quality'),
    orientation: (0, pg_core_1.text)('orientation'),
    hasAudio: (0, pg_core_1.boolean)('has_audio').default(true),
    fileSize: (0, pg_core_1.bigint)('file_size', { mode: 'number' }),
    fileHash: (0, pg_core_1.text)('file_hash'),
    width: (0, pg_core_1.integer)('width'),
    height: (0, pg_core_1.integer)('height'),
    lastValidated: (0, pg_core_1.timestamp)('last_validated', { withTimezone: true }),
    isValid: (0, pg_core_1.boolean)('is_valid').default(true),
    thumbnailPath: (0, pg_core_1.text)('thumbnail_path'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    tags: (0, pg_core_1.jsonb)('tags').$type(),
    // Directory type for efficient filtering (indexed)
    directoryType: (0, pg_core_1.text)('directory_type').$type(),
    // Historical engagement stats (preserved when moved from public media)
    publicViewCount: (0, pg_core_1.integer)('public_view_count'),
    publicUpvoteCount: (0, pg_core_1.integer)('public_upvote_count'),
    publicCommentCount: (0, pg_core_1.integer)('public_comment_count'),
    publicCompletionCount: (0, pg_core_1.integer)('public_completion_count'),
    publicTotalWatchTime: (0, pg_core_1.integer)('public_total_watch_time'),
    movedFromPublicAt: (0, pg_core_1.timestamp)('moved_from_public_at', { withTimezone: true }),
    // Name standardization tracking
    originalFilename: (0, pg_core_1.text)('original_filename'),
    originalPath: (0, pg_core_1.text)('original_path'),
    standardizedAt: (0, pg_core_1.timestamp)('standardized_at', { withTimezone: true }),
}, (table) => ({
    orientationIdx: (0, pg_core_1.index)('idx_orientation').on(table.orientation),
    producerIdx: (0, pg_core_1.index)('idx_producer').on(table.producer),
    isValidIdx: (0, pg_core_1.index)('idx_is_valid').on(table.isValid),
    directoryTypeIdx: (0, pg_core_1.index)('idx_directory_type').on(table.directoryType),
    fingerprintIdx: (0, pg_core_1.index)('idx_videos_fingerprint').on(table.durationSeconds, table.fileSize, table.width, table.height),
    // Composite index for common filtering pattern (directory + valid + orientation)
    directoryValidOrientationIdx: (0, pg_core_1.index)('idx_videos_directory_valid_orientation').on(table.directoryType, table.isValid, table.orientation),
}));
exports.compilations = (0, pg_core_1.pgTable)('compilations', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    filename: (0, pg_core_1.text)('filename').notNull(),
    path: (0, pg_core_1.text)('path'),
    durationSeconds: (0, pg_core_1.integer)('duration_seconds'),
    videoIds: (0, pg_core_1.jsonb)('video_ids').$type(),
    settings: (0, pg_core_1.jsonb)('settings').$type(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
});
exports.jobs = (0, pg_core_1.pgTable)('jobs', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    type: (0, pg_core_1.text)('type').notNull(),
    status: (0, pg_core_1.text)('status').default('pending').$type(),
    progress: (0, pg_core_1.integer)('progress').default(0),
    log: (0, pg_core_1.text)('log'),
    params: (0, pg_core_1.jsonb)('params').$type(),
    startedAt: (0, pg_core_1.timestamp)('started_at', { withTimezone: true }),
    completedAt: (0, pg_core_1.timestamp)('completed_at', { withTimezone: true }),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    // Queue management columns
    resourceCategory: (0, pg_core_1.text)('resource_category').default('cpu').$type(),
    vramRequired: (0, pg_core_1.integer)('vram_required').default(0),
    queuePosition: (0, pg_core_1.integer)('queue_position'),
    waitingReason: (0, pg_core_1.text)('waiting_reason'),
    priority: (0, pg_core_1.integer)('priority').default(5),
    // Pipeline integration (optional - for jobs created via pipeline)
    pipelineId: (0, pg_core_1.integer)('pipeline_id'),
    pipelineStepId: (0, pg_core_1.integer)('pipeline_step_id'),
}, (table) => ({
    queueIdx: (0, pg_core_1.index)('idx_jobs_queue').on(table.status, table.priority, table.createdAt),
    resourceIdx: (0, pg_core_1.index)('idx_jobs_resource').on(table.resourceCategory, table.status),
    pipelineIdx: (0, pg_core_1.index)('idx_jobs_pipeline').on(table.pipelineId),
}));
// ============================================
// Public Gallery Tables
// ============================================
exports.publicMedia = (0, pg_core_1.pgTable)('public_media', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    path: (0, pg_core_1.text)('path').notNull().unique(),
    filename: (0, pg_core_1.text)('filename').notNull(),
    category: (0, pg_core_1.text)('category').notNull(),
    durationSeconds: (0, pg_core_1.integer)('duration_seconds'),
    quality: (0, pg_core_1.text)('quality'),
    orientation: (0, pg_core_1.text)('orientation'),
    thumbnailPath: (0, pg_core_1.text)('thumbnail_path'),
    fileSize: (0, pg_core_1.bigint)('file_size', { mode: 'number' }),
    // Denormalized counters for performance
    viewCount: (0, pg_core_1.integer)('view_count').default(0),
    upvoteCount: (0, pg_core_1.integer)('upvote_count').default(0),
    commentCount: (0, pg_core_1.integer)('comment_count').default(0),
    finishCount: (0, pg_core_1.integer)('finish_count').default(0),
    totalWatchTime: (0, pg_core_1.integer)('total_watch_time').default(0),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    // Locked video system
    isLocked: (0, pg_core_1.boolean)('is_locked').default(false),
    lockedAt: (0, pg_core_1.timestamp)('locked_at', { withTimezone: true }),
    lockedBy: (0, pg_core_1.integer)('locked_by'),
    // Manual ordering for playlist (curated category)
    position: (0, pg_core_1.integer)('position').default(0),
    // Track uploader for quickies
    uploaderId: (0, pg_core_1.integer)('uploader_id'),
}, (table) => ({
    categoryIdx: (0, pg_core_1.index)('idx_public_media_category').on(table.category),
    pathIdx: (0, pg_core_1.index)('idx_public_media_path').on(table.path),
    isLockedIdx: (0, pg_core_1.index)('idx_public_media_is_locked').on(table.isLocked),
    positionIdx: (0, pg_core_1.index)('idx_public_media_position').on(table.position),
    // Quickies performance indexes
    uploaderIdx: (0, pg_core_1.index)('idx_public_media_uploader').on(table.uploaderId),
    categoryDateIdx: (0, pg_core_1.index)('idx_public_media_category_date').on(table.category, table.createdAt),
    orientationIdx: (0, pg_core_1.index)('idx_public_media_orientation').on(table.orientation),
    // Composite index for common filtering (category + locked + date)
    categoryLockedDateIdx: (0, pg_core_1.index)('idx_public_media_category_locked_date').on(table.category, table.isLocked, table.createdAt),
}));
exports.sessions = (0, pg_core_1.pgTable)('sessions', {
    id: (0, pg_core_1.text)('id').primaryKey(), // UUID from client
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    lastSeenAt: (0, pg_core_1.timestamp)('last_seen_at', { withTimezone: true }),
    // Device tracking
    ipAddress: (0, pg_core_1.text)('ip_address'),
    userAgent: (0, pg_core_1.text)('user_agent'),
    deviceType: (0, pg_core_1.text)('device_type'), // 'desktop' | 'mobile' | 'tablet'
    browser: (0, pg_core_1.text)('browser'),
    os: (0, pg_core_1.text)('os'),
    // Geography (from GeoIP)
    country: (0, pg_core_1.text)('country'), // ISO code: 'US'
    countryName: (0, pg_core_1.text)('country_name'), // 'United States'
    region: (0, pg_core_1.text)('region'), // 'CA'
    city: (0, pg_core_1.text)('city'), // 'Los Angeles'
    timezone: (0, pg_core_1.text)('timezone'), // 'America/Los_Angeles'
    latitude: (0, pg_core_1.real)('latitude'),
    longitude: (0, pg_core_1.real)('longitude'),
    // User correlation
    userId: (0, pg_core_1.integer)('user_id'), // Links session to authenticated user
    // Analytics
    firstSeenAt: (0, pg_core_1.timestamp)('first_seen_at', { withTimezone: true }), // For return visitor detection
    visitCount: (0, pg_core_1.integer)('visit_count').default(1), // Increment on return visits
}, (table) => ({
    userIdIdx: (0, pg_core_1.index)('idx_sessions_user_id').on(table.userId),
    countryIdx: (0, pg_core_1.index)('idx_sessions_country').on(table.country),
}));
exports.upvotes = (0, pg_core_1.pgTable)('upvotes', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    sessionId: (0, pg_core_1.text)('session_id').notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    uniqueVoteIdx: (0, pg_core_1.index)('idx_upvotes_unique').on(table.mediaId, table.sessionId),
    mediaIdx: (0, pg_core_1.index)('idx_upvotes_media').on(table.mediaId),
}));
exports.comments = (0, pg_core_1.pgTable)('comments', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    sessionId: (0, pg_core_1.text)('session_id').notNull(),
    userId: (0, pg_core_1.integer)('user_id'),
    content: (0, pg_core_1.text)('content').notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    // Content safety fields for LLM-based moderation
    safetyStatus: (0, pg_core_1.text)('safety_status').default('pending'),
    safetyCheckedAt: (0, pg_core_1.timestamp)('safety_checked_at', { withTimezone: true }),
    safetyCategories: (0, pg_core_1.jsonb)('safety_categories').$type(),
    safetyReasoning: (0, pg_core_1.text)('safety_reasoning'),
    // Hidden comment fields for auto-moderation
    isHidden: (0, pg_core_1.boolean)('is_hidden').default(false),
    hiddenAt: (0, pg_core_1.timestamp)('hidden_at', { withTimezone: true }),
    hiddenReason: (0, pg_core_1.text)('hidden_reason'),
    // Admin moderation notes (internal, not shown to users)
    moderationNotes: (0, pg_core_1.text)('moderation_notes'),
}, (table) => ({
    mediaIdx: (0, pg_core_1.index)('idx_comments_media').on(table.mediaId),
    sessionIdx: (0, pg_core_1.index)('idx_comments_session').on(table.sessionId),
    userIdx: (0, pg_core_1.index)('idx_comments_user').on(table.userId),
    safetyStatusIdx: (0, pg_core_1.index)('idx_comments_safety_status').on(table.safetyStatus),
    isHiddenIdx: (0, pg_core_1.index)('idx_comments_is_hidden').on(table.isHidden),
}));
exports.views = (0, pg_core_1.pgTable)('views', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    sessionId: (0, pg_core_1.text)('session_id').notNull(),
    watchTimeSeconds: (0, pg_core_1.integer)('watch_time_seconds').default(0),
    lastUpdated: (0, pg_core_1.timestamp)('last_updated', { withTimezone: true }).defaultNow(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    uniqueViewIdx: (0, pg_core_1.index)('idx_views_unique').on(table.mediaId, table.sessionId),
    mediaIdx: (0, pg_core_1.index)('idx_views_media').on(table.mediaId),
}));
// ============================================
// User Management Tables
// ============================================
// V2 Users table (for authentication only)
// This matches the Prisma User model to allow Drizzle queries for auth
// Table name: 'users' (created by Prisma migrations)
exports.v2Users = (0, pg_core_1.pgTable)('users', {
    id: (0, pg_core_1.text)('id').primaryKey(),
    email: (0, pg_core_1.text)('email').notNull().unique(),
    password: (0, pg_core_1.text)('password').notNull(),
    name: (0, pg_core_1.text)('name'),
    phone: (0, pg_core_1.text)('phone'),
    role: (0, pg_core_1.text)('role').notNull().default('USER'),
    status: (0, pg_core_1.text)('status').notNull().default('ACTIVE'),
    permissions: (0, pg_core_1.jsonb)('permissions'),
    createdVia: (0, pg_core_1.text)('createdVia').notNull().default('STANDARD'),
    expiresAt: (0, pg_core_1.timestamp)('expiresAt', { withTimezone: true }),
    expireDays: (0, pg_core_1.integer)('expireDays'),
    lastLoginAt: (0, pg_core_1.timestamp)('lastLoginAt', { withTimezone: true }),
    emailVerified: (0, pg_core_1.boolean)('emailVerified').notNull().default(false),
    createdAt: (0, pg_core_1.timestamp)('createdAt', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updatedAt', { withTimezone: true }).notNull().defaultNow(),
}, (table) => ({
    emailIdx: (0, pg_core_1.index)('User_email_key').on(table.email),
}));
// Media-specific users table (for future media-api user management)
// NOTE: This is separate from v2Users and not currently used
// If/when media-api needs its own user system, this table can be created
exports.mediaUsers = (0, pg_core_1.pgTable)('media_users', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    username: (0, pg_core_1.text)('username').notNull().unique(),
    email: (0, pg_core_1.text)('email').notNull().unique(),
    passwordHash: (0, pg_core_1.text)('password_hash').notNull(),
    role: (0, pg_core_1.text)('role').notNull().default('user'),
    status: (0, pg_core_1.text)('status').notNull().default('pending'),
    emailVerified: (0, pg_core_1.boolean)('email_verified').default(false),
    linkedSessionId: (0, pg_core_1.text)('linked_session_id'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    approvedAt: (0, pg_core_1.timestamp)('approved_at', { withTimezone: true }),
    approvedBy: (0, pg_core_1.integer)('approved_by'),
    lastLoginAt: (0, pg_core_1.timestamp)('last_login_at', { withTimezone: true }),
    // Trusted user fields
    isTrusted: (0, pg_core_1.boolean)('is_trusted').default(false),
    maxUploadDurationSeconds: (0, pg_core_1.integer)('max_upload_duration_seconds').default(60),
    autoAcceptUploads: (0, pg_core_1.boolean)('auto_accept_uploads').default(false),
    trustedAt: (0, pg_core_1.timestamp)('trusted_at', { withTimezone: true }),
    trustedBy: (0, pg_core_1.integer)('trusted_by'),
    defaultPlaylistId: (0, pg_core_1.integer)('default_playlist_id'),
    // Social links visibility
    socialLinksPublic: (0, pg_core_1.boolean)('social_links_public').default(false),
    // Subscription fields
    subscriptionStatus: (0, pg_core_1.text)('subscription_status').default('none'), // none, active, grace_period, delinquent, lifetime
    subscriptionPlanId: (0, pg_core_1.integer)('subscription_plan_id'),
    subscriptionEndDate: (0, pg_core_1.timestamp)('subscription_end_date', { withTimezone: true }),
    lifetimeMember: (0, pg_core_1.boolean)('lifetime_member').default(false),
    totalPaidCAD: (0, pg_core_1.integer)('total_paid_cad').default(0), // Lifetime total in cents
    // Moderation tracking
    lastModerationAction: (0, pg_core_1.timestamp)('last_moderation_action', { withTimezone: true }),
}, (table) => ({
    emailIdx: (0, pg_core_1.index)('idx_media_users_email').on(table.email),
    usernameIdx: (0, pg_core_1.index)('idx_media_users_username').on(table.username),
    statusIdx: (0, pg_core_1.index)('idx_media_users_status').on(table.status),
    trustedIdx: (0, pg_core_1.index)('idx_media_users_trusted').on(table.isTrusted),
    subscriptionStatusIdx: (0, pg_core_1.index)('idx_media_users_subscription_status').on(table.subscriptionStatus),
}));
exports.authTokens = (0, pg_core_1.pgTable)('auth_tokens', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    token: (0, pg_core_1.text)('token').notNull().unique(),
    type: (0, pg_core_1.text)('type').notNull(),
    expiresAt: (0, pg_core_1.timestamp)('expires_at', { withTimezone: true }).notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    tokenIdx: (0, pg_core_1.index)('idx_auth_tokens_token').on(table.token),
    userIdx: (0, pg_core_1.index)('idx_auth_tokens_user').on(table.userId),
}));
exports.sessionBans = (0, pg_core_1.pgTable)('session_bans', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    sessionId: (0, pg_core_1.text)('session_id').notNull(),
    reason: (0, pg_core_1.text)('reason'),
    bannedBy: (0, pg_core_1.integer)('banned_by'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    expiresAt: (0, pg_core_1.timestamp)('expires_at', { withTimezone: true }), // null = permanent
}, (table) => ({
    sessionIdx: (0, pg_core_1.index)('idx_session_bans_session').on(table.sessionId),
}));
exports.commentModeration = (0, pg_core_1.pgTable)('comment_moderation', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    commentId: (0, pg_core_1.integer)('comment_id').notNull(),
    status: (0, pg_core_1.text)('status').notNull().default('pending'),
    moderatedBy: (0, pg_core_1.integer)('moderated_by'),
    moderatedAt: (0, pg_core_1.timestamp)('moderated_at', { withTimezone: true }),
    reason: (0, pg_core_1.text)('reason'),
}, (table) => ({
    commentIdx: (0, pg_core_1.index)('idx_comment_moderation_comment').on(table.commentId),
    statusIdx: (0, pg_core_1.index)('idx_comment_moderation_status').on(table.status),
}));
// Email Verification Tokens
exports.emailVerificationTokens = (0, pg_core_1.pgTable)('email_verification_tokens', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    token: (0, pg_core_1.text)('token').notNull().unique(),
    expiresAt: (0, pg_core_1.timestamp)('expires_at', { withTimezone: true }).notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    tokenIdx: (0, pg_core_1.index)('idx_email_verification_tokens_token').on(table.token),
    userIdx: (0, pg_core_1.index)('idx_email_verification_tokens_user').on(table.userId),
}));
// Password Reset Tokens
exports.passwordResetTokens = (0, pg_core_1.pgTable)('password_reset_tokens', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    token: (0, pg_core_1.text)('token').notNull().unique(),
    expiresAt: (0, pg_core_1.timestamp)('expires_at', { withTimezone: true }).notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    usedAt: (0, pg_core_1.timestamp)('used_at', { withTimezone: true }),
}, (table) => ({
    tokenIdx: (0, pg_core_1.index)('idx_password_reset_tokens_token').on(table.token),
    userIdx: (0, pg_core_1.index)('idx_password_reset_tokens_user').on(table.userId),
}));
// Email Change Tokens
exports.emailChangeTokens = (0, pg_core_1.pgTable)('email_change_tokens', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    newEmail: (0, pg_core_1.text)('new_email').notNull(),
    token: (0, pg_core_1.text)('token').notNull().unique(),
    expiresAt: (0, pg_core_1.timestamp)('expires_at', { withTimezone: true }).notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    tokenIdx: (0, pg_core_1.index)('idx_email_change_tokens_token').on(table.token),
    userIdx: (0, pg_core_1.index)('idx_email_change_tokens_user').on(table.userId),
}));
// ============================================
// Achievement & Dashboard Tables
// ============================================
exports.userAchievements = (0, pg_core_1.pgTable)('user_achievements', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    achievementId: (0, pg_core_1.text)('achievement_id').notNull(),
    unlockedAt: (0, pg_core_1.timestamp)('unlocked_at', { withTimezone: true }).notNull(),
    progress: (0, pg_core_1.integer)('progress').default(0),
    notified: (0, pg_core_1.boolean)('notified').default(false),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_user_achievements_user').on(table.userId),
    // Unique constraint for ON CONFLICT support in batch inserts
    userAchievementUnique: (0, pg_core_1.uniqueIndex)('idx_user_achievements_unique').on(table.userId, table.achievementId),
}));
exports.userStats = (0, pg_core_1.pgTable)('user_stats', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull().unique(),
    totalWatchTimeSeconds: (0, pg_core_1.integer)('total_watch_time_seconds').default(0),
    totalVideosWatched: (0, pg_core_1.integer)('total_videos_watched').default(0),
    totalUpvotesGiven: (0, pg_core_1.integer)('total_upvotes_given').default(0),
    totalCommentsMade: (0, pg_core_1.integer)('total_comments_made').default(0),
    totalFinishes: (0, pg_core_1.integer)('total_finishes').default(0),
    currentDayStreak: (0, pg_core_1.integer)('current_day_streak').default(0),
    longestDayStreak: (0, pg_core_1.integer)('longest_day_streak').default(0),
    lastActiveDate: (0, pg_core_1.text)('last_active_date'), // YYYY-MM-DD format
    longestSingleSession: (0, pg_core_1.integer)('longest_single_session').default(0),
    categoriesCompleted: (0, pg_core_1.jsonb)('categories_completed').$type(),
    nightOwlCount: (0, pg_core_1.integer)('night_owl_count').default(0),
    earlyBirdCount: (0, pg_core_1.integer)('early_bird_count').default(0),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }),
});
exports.userFinishes = (0, pg_core_1.pgTable)('user_finishes', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    mediaId: (0, pg_core_1.integer)('media_id'),
    sessionId: (0, pg_core_1.text)('session_id'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).notNull(),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_user_finishes_user').on(table.userId),
    dateIdx: (0, pg_core_1.index)('idx_user_finishes_date').on(table.createdAt),
}));
// ============================================
// Video Reactions Table
// ============================================
exports.REACTION_TYPES = ['like', 'love', 'laugh', 'wow', 'sad', 'angry'];
exports.videoReactions = (0, pg_core_1.pgTable)('video_reactions', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    reactionType: (0, pg_core_1.text)('reaction_type').notNull(),
    videoTimestamp: (0, pg_core_1.integer)('video_timestamp').notNull(), // seconds into the video when reaction was clicked
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).notNull(),
}, (table) => ({
    userMediaTypeIdx: (0, pg_core_1.index)('idx_video_reactions_user_media_type').on(table.userId, table.mediaId, table.reactionType),
    mediaTimestampIdx: (0, pg_core_1.index)('idx_video_reactions_media_timestamp').on(table.mediaId, table.videoTimestamp),
    mediaIdx: (0, pg_core_1.index)('idx_video_reactions_media').on(table.mediaId),
    createdAtIdx: (0, pg_core_1.index)('idx_video_reactions_created').on(table.createdAt),
}));
// ============================================
// Quickie Generation Cooldowns Table
// ============================================
exports.highlightCooldowns = (0, pg_core_1.pgTable)('highlight_cooldowns', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    lastGeneratedAt: (0, pg_core_1.timestamp)('last_generated_at', { withTimezone: true }).notNull(),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_highlight_cooldowns_user').on(table.userId),
}));
exports.userDailyActivity = (0, pg_core_1.pgTable)('user_daily_activity', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    activityDate: (0, pg_core_1.text)('activity_date').notNull(), // YYYY-MM-DD
    watchTimeSeconds: (0, pg_core_1.integer)('watch_time_seconds').default(0),
    videosWatched: (0, pg_core_1.integer)('videos_watched').default(0),
    firstActivityHour: (0, pg_core_1.integer)('first_activity_hour'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }),
}, (table) => ({
    uniqueIdx: (0, pg_core_1.index)('idx_user_daily_activity_unique').on(table.userId, table.activityDate),
}));
// ============================================
// Chat Thread Tracking Table
// ============================================
exports.chatThreadReadStatus = (0, pg_core_1.pgTable)('chat_thread_read_status', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    lastSeenAt: (0, pg_core_1.timestamp)('last_seen_at', { withTimezone: true }).notNull(),
}, (table) => ({
    uniqueIdx: (0, pg_core_1.index)('idx_chat_thread_read_unique').on(table.userId, table.mediaId),
    userIdx: (0, pg_core_1.index)('idx_chat_thread_read_user').on(table.userId),
}));
// ============================================
// App Settings Table
// ============================================
exports.appSettings = (0, pg_core_1.pgTable)('app_settings', {
    key: (0, pg_core_1.text)('key').primaryKey(),
    value: (0, pg_core_1.text)('value').notNull(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }).defaultNow(),
});
// ============================================
// Rate Limiting Table (for persistent rate limits)
// ============================================
exports.rateLimits = (0, pg_core_1.pgTable)('rate_limits', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    key: (0, pg_core_1.text)('key').notNull().unique(),
    count: (0, pg_core_1.integer)('count').notNull().default(1),
    resetAt: (0, pg_core_1.timestamp)('reset_at', { withTimezone: true }).notNull(),
}, (table) => ({
    keyIdx: (0, pg_core_1.uniqueIndex)('idx_rate_limits_key').on(table.key),
    resetAtIdx: (0, pg_core_1.index)('idx_rate_limits_reset_at').on(table.resetAt),
}));
// ============================================
// Moderation Word Lists Table
// ============================================
exports.WORD_FILTER_LEVELS = ['low', 'medium', 'high', 'custom'];
exports.moderationWordLists = (0, pg_core_1.pgTable)('moderation_word_lists', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    level: (0, pg_core_1.text)('level').notNull(),
    word: (0, pg_core_1.text)('word').notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    createdBy: (0, pg_core_1.integer)('created_by'),
}, (table) => ({
    levelIdx: (0, pg_core_1.index)('idx_moderation_word_lists_level').on(table.level),
    wordIdx: (0, pg_core_1.index)('idx_moderation_word_lists_word').on(table.word),
}));
// ============================================
// Content Reports Table
// ============================================
exports.REPORT_TYPES = ['inappropriate', 'spam', 'copyright', 'illegal', 'false_info', 'other'];
exports.REPORT_STATUS = ['pending', 'reviewed', 'actioned', 'dismissed'];
exports.contentReports = (0, pg_core_1.pgTable)('content_reports', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    sessionId: (0, pg_core_1.text)('session_id'),
    userId: (0, pg_core_1.integer)('user_id'),
    reportType: (0, pg_core_1.text)('report_type').notNull(),
    description: (0, pg_core_1.text)('description'),
    status: (0, pg_core_1.text)('status').notNull().default('pending'),
    resolvedBy: (0, pg_core_1.integer)('resolved_by'),
    resolvedAt: (0, pg_core_1.timestamp)('resolved_at', { withTimezone: true }),
    resolutionNotes: (0, pg_core_1.text)('resolution_notes'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    mediaIdx: (0, pg_core_1.index)('idx_content_reports_media').on(table.mediaId),
    statusIdx: (0, pg_core_1.index)('idx_content_reports_status').on(table.status),
    sessionIdx: (0, pg_core_1.index)('idx_content_reports_session').on(table.sessionId),
    createdAtIdx: (0, pg_core_1.index)('idx_content_reports_created').on(table.createdAt),
}));
// ============================================
// Playlist Tables
// ============================================
exports.playlists = (0, pg_core_1.pgTable)('playlists', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    name: (0, pg_core_1.text)('name').notNull(),
    description: (0, pg_core_1.text)('description'),
    isPublic: (0, pg_core_1.boolean)('is_public').default(false),
    shareToken: (0, pg_core_1.text)('share_token').unique(),
    thumbnailMediaId: (0, pg_core_1.integer)('thumbnail_media_id'),
    // Denormalized counters
    videoCount: (0, pg_core_1.integer)('video_count').default(0),
    totalDurationSeconds: (0, pg_core_1.integer)('total_duration_seconds').default(0),
    viewCount: (0, pg_core_1.integer)('view_count').default(0),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_playlists_user').on(table.userId),
    publicIdx: (0, pg_core_1.index)('idx_playlists_public').on(table.isPublic),
    shareTokenIdx: (0, pg_core_1.index)('idx_playlists_share_token').on(table.shareToken),
    // Prevent duplicate playlist names per user (e.g., multiple "My Quickies")
    userNameIdx: (0, pg_core_1.uniqueIndex)('idx_playlists_user_name').on(table.userId, table.name),
}));
exports.playlistVideos = (0, pg_core_1.pgTable)('playlist_videos', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    playlistId: (0, pg_core_1.integer)('playlist_id').notNull(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    position: (0, pg_core_1.integer)('position').notNull().default(0),
    addedAt: (0, pg_core_1.timestamp)('added_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    playlistIdx: (0, pg_core_1.index)('idx_playlist_videos_playlist').on(table.playlistId),
    mediaIdx: (0, pg_core_1.index)('idx_playlist_videos_media').on(table.mediaId),
    uniqueIdx: (0, pg_core_1.index)('idx_playlist_videos_unique').on(table.playlistId, table.mediaId),
}));
exports.featuredPlaylists = (0, pg_core_1.pgTable)('featured_playlists', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    playlistId: (0, pg_core_1.integer)('playlist_id').notNull().unique(),
    position: (0, pg_core_1.integer)('position').notNull().default(0),
    featuredBy: (0, pg_core_1.integer)('featured_by'),
    featuredAt: (0, pg_core_1.timestamp)('featured_at', { withTimezone: true }),
}, (table) => ({
    positionIdx: (0, pg_core_1.index)('idx_featured_playlists_position').on(table.position),
}));
exports.playlistViews = (0, pg_core_1.pgTable)('playlist_views', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    playlistId: (0, pg_core_1.integer)('playlist_id').notNull(),
    sessionId: (0, pg_core_1.text)('session_id').notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    playlistIdx: (0, pg_core_1.index)('idx_playlist_views_playlist').on(table.playlistId),
    uniqueIdx: (0, pg_core_1.index)('idx_playlist_views_unique').on(table.playlistId, table.sessionId),
}));
// ============================================
// Advertisement Tables
// ============================================
exports.ads = (0, pg_core_1.pgTable)('ads', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    type: (0, pg_core_1.text)('type').notNull(),
    // For make_account: variant identifier (e.g., 'playlist_promo', 'chat_promo')
    // For custom: null (uses imagePath instead)
    variant: (0, pg_core_1.text)('variant'),
    // Custom ad fields
    imagePath: (0, pg_core_1.text)('image_path'),
    linkUrl: (0, pg_core_1.text)('link_url'),
    title: (0, pg_core_1.text)('title'), // For alt text and admin reference
    // Visibility: 'everyone', 'members_only', 'non_members'
    visibility: (0, pg_core_1.text)('visibility').notNull().default('everyone'),
    // Status
    isActive: (0, pg_core_1.boolean)('is_active').default(true),
    // Ordering for rotation
    position: (0, pg_core_1.integer)('position').default(0),
    // Denormalized counters for performance
    impressionCount: (0, pg_core_1.integer)('impression_count').default(0),
    clickCount: (0, pg_core_1.integer)('click_count').default(0),
    // Timestamps
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }),
}, (table) => ({
    typeIdx: (0, pg_core_1.index)('idx_ads_type').on(table.type),
    isActiveIdx: (0, pg_core_1.index)('idx_ads_is_active').on(table.isActive),
    visibilityIdx: (0, pg_core_1.index)('idx_ads_visibility').on(table.visibility),
}));
exports.adImpressions = (0, pg_core_1.pgTable)('ad_impressions', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    adId: (0, pg_core_1.integer)('ad_id').notNull().references(() => exports.ads.id, { onDelete: 'cascade' }),
    sessionId: (0, pg_core_1.text)('session_id'),
    userId: (0, pg_core_1.integer)('user_id'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    adIdx: (0, pg_core_1.index)('idx_ad_impressions_ad').on(table.adId),
    sessionIdx: (0, pg_core_1.index)('idx_ad_impressions_session').on(table.sessionId),
    dateIdx: (0, pg_core_1.index)('idx_ad_impressions_date').on(table.createdAt),
}));
exports.adClicks = (0, pg_core_1.pgTable)('ad_clicks', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    adId: (0, pg_core_1.integer)('ad_id').notNull().references(() => exports.ads.id, { onDelete: 'cascade' }),
    sessionId: (0, pg_core_1.text)('session_id'),
    userId: (0, pg_core_1.integer)('user_id'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    adIdx: (0, pg_core_1.index)('idx_ad_clicks_ad').on(table.adId),
    sessionIdx: (0, pg_core_1.index)('idx_ad_clicks_session').on(table.sessionId),
    dateIdx: (0, pg_core_1.index)('idx_ad_clicks_date').on(table.createdAt),
}));
// ============================================
// Friends & Social Tables
// ============================================
exports.FRIENDSHIP_STATUS = ['pending', 'accepted', 'declined'];
exports.friendships = (0, pg_core_1.pgTable)('friendships', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    friendId: (0, pg_core_1.integer)('friend_id').notNull(),
    status: (0, pg_core_1.text)('status').notNull().default('pending'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    acceptedAt: (0, pg_core_1.timestamp)('accepted_at', { withTimezone: true }),
}, (table) => ({
    userFriendIdx: (0, pg_core_1.index)('idx_friendships_user_friend').on(table.userId, table.friendId),
    userIdx: (0, pg_core_1.index)('idx_friendships_user').on(table.userId),
    friendIdx: (0, pg_core_1.index)('idx_friendships_friend').on(table.friendId),
    statusIdx: (0, pg_core_1.index)('idx_friendships_status').on(table.status),
}));
exports.userBlocks = (0, pg_core_1.pgTable)('user_blocks', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    blockedUserId: (0, pg_core_1.integer)('blocked_user_id').notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    uniqueBlockIdx: (0, pg_core_1.index)('idx_user_blocks_unique').on(table.userId, table.blockedUserId),
    userIdx: (0, pg_core_1.index)('idx_user_blocks_user').on(table.userId),
}));
exports.pokes = (0, pg_core_1.pgTable)('pokes', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    fromUserId: (0, pg_core_1.integer)('from_user_id').notNull(),
    toUserId: (0, pg_core_1.integer)('to_user_id').notNull(),
    isRead: (0, pg_core_1.boolean)('is_read').default(false),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    toUserIdx: (0, pg_core_1.index)('idx_pokes_to_user').on(table.toUserId),
    fromUserIdx: (0, pg_core_1.index)('idx_pokes_from_user').on(table.fromUserId),
}));
// Video recommendations - share videos with friends
exports.videoRecommendations = (0, pg_core_1.pgTable)('video_recommendations', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    fromUserId: (0, pg_core_1.integer)('from_user_id').notNull(),
    toUserId: (0, pg_core_1.integer)('to_user_id').notNull(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    message: (0, pg_core_1.text)('message'),
    isRead: (0, pg_core_1.boolean)('is_read').default(false),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    toUserIdx: (0, pg_core_1.index)('idx_video_recommendations_to_user').on(table.toUserId),
    fromUserIdx: (0, pg_core_1.index)('idx_video_recommendations_from_user').on(table.fromUserId),
    mediaIdx: (0, pg_core_1.index)('idx_video_recommendations_media').on(table.mediaId),
}));
exports.userPresence = (0, pg_core_1.pgTable)('user_presence', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull().unique(),
    isOnline: (0, pg_core_1.boolean)('is_online').default(false),
    currentMediaId: (0, pg_core_1.integer)('current_media_id'),
    lastActivityAt: (0, pg_core_1.timestamp)('last_activity_at', { withTimezone: true }),
    lastVideoChangeAt: (0, pg_core_1.timestamp)('last_video_change_at', { withTimezone: true }),
}, (table) => ({
    onlineIdx: (0, pg_core_1.index)('idx_user_presence_online').on(table.isOnline),
    userIdx: (0, pg_core_1.index)('idx_user_presence_user').on(table.userId),
}));
exports.userGalleryImages = (0, pg_core_1.pgTable)('user_gallery_images', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    filename: (0, pg_core_1.text)('filename').notNull(),
    originalFilename: (0, pg_core_1.text)('original_filename'),
    position: (0, pg_core_1.integer)('position').notNull().default(0),
    uploadedAt: (0, pg_core_1.timestamp)('uploaded_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_user_gallery_user').on(table.userId),
    positionIdx: (0, pg_core_1.index)('idx_user_gallery_position').on(table.userId, table.position),
}));
// Social link platforms
exports.SOCIAL_PLATFORMS = [
    'twitter', 'instagram', 'onlyfans', 'fansly', 'reddit',
    'discord', 'tiktok', 'youtube', 'twitch', 'snapchat',
    'linktree', 'custom'
];
exports.userSocialLinks = (0, pg_core_1.pgTable)('user_social_links', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    platform: (0, pg_core_1.text)('platform').notNull(), // One of SOCIAL_PLATFORMS
    url: (0, pg_core_1.text)('url').notNull(),
    displayName: (0, pg_core_1.text)('display_name'), // Optional custom label
    position: (0, pg_core_1.integer)('position').notNull().default(0),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_user_social_links_user').on(table.userId),
    positionIdx: (0, pg_core_1.index)('idx_user_social_links_position').on(table.userId, table.position),
}));
// ============================================
// Privacy Settings Tables
// ============================================
exports.privacySettings = (0, pg_core_1.pgTable)('privacy_settings', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull().unique().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    // Online Status
    showOnlineStatus: (0, pg_core_1.boolean)('show_online_status').default(true),
    showCurrentlyWatching: (0, pg_core_1.boolean)('show_currently_watching').default(true),
    // Activity Visibility
    showInFriendActivity: (0, pg_core_1.boolean)('show_in_friend_activity').default(true),
    anonymizePublicComments: (0, pg_core_1.boolean)('anonymize_public_comments').default(false),
    hidePublicReactions: (0, pg_core_1.boolean)('hide_public_reactions').default(false),
    hidePublicFinishes: (0, pg_core_1.boolean)('hide_public_finishes').default(false),
    // Friend Requests
    allowFriendRequests: (0, pg_core_1.boolean)('allow_friend_requests').default(true),
    // Close Friends restrictions
    closeFriendsOnlyWatching: (0, pg_core_1.boolean)('close_friends_only_watching').default(false),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_privacy_settings_user').on(table.userId),
}));
exports.closeFriends = (0, pg_core_1.pgTable)('close_friends', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    closeFriendId: (0, pg_core_1.integer)('close_friend_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    addedAt: (0, pg_core_1.timestamp)('added_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    uniqueIdx: (0, pg_core_1.uniqueIndex)('idx_close_friends_unique').on(table.userId, table.closeFriendId),
    userIdx: (0, pg_core_1.index)('idx_close_friends_user').on(table.userId),
}));
// ============================================
// User Uploads (Trusted User Feature)
// ============================================
exports.USER_UPLOAD_STATUS = ['pending', 'approved', 'rejected'];
exports.userUploads = (0, pg_core_1.pgTable)('user_uploads', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    filename: (0, pg_core_1.text)('filename').notNull(),
    originalFilename: (0, pg_core_1.text)('original_filename'),
    path: (0, pg_core_1.text)('path').notNull(),
    durationSeconds: (0, pg_core_1.integer)('duration_seconds'),
    quality: (0, pg_core_1.text)('quality'),
    orientation: (0, pg_core_1.text)('orientation'),
    fileSize: (0, pg_core_1.bigint)('file_size', { mode: 'number' }),
    thumbnailPath: (0, pg_core_1.text)('thumbnail_path'),
    status: (0, pg_core_1.text)('status').notNull().default('pending'),
    reviewedBy: (0, pg_core_1.integer)('reviewed_by'),
    reviewedAt: (0, pg_core_1.timestamp)('reviewed_at', { withTimezone: true }),
    reviewNotes: (0, pg_core_1.text)('review_notes'),
    publicMediaId: (0, pg_core_1.integer)('public_media_id'),
    uploadInviteId: (0, pg_core_1.integer)('upload_invite_id'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_user_uploads_user').on(table.userId),
    statusIdx: (0, pg_core_1.index)('idx_user_uploads_status').on(table.status),
    createdAtIdx: (0, pg_core_1.index)('idx_user_uploads_created').on(table.createdAt),
    inviteIdx: (0, pg_core_1.index)('idx_user_uploads_invite').on(table.uploadInviteId),
}));
// ============================================
// Upload Invites (Shareable Upload Links)
// ============================================
exports.UPLOAD_INVITE_STATUS = ['active', 'inactive', 'expired'];
exports.uploadInvites = (0, pg_core_1.pgTable)('upload_invites', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    code: (0, pg_core_1.text)('code').notNull().unique(),
    label: (0, pg_core_1.text)('label'),
    createdBy: (0, pg_core_1.integer)('created_by').notNull(),
    status: (0, pg_core_1.text)('status').notNull().default('active'),
    maxUploads: (0, pg_core_1.integer)('max_uploads'),
    uploadCount: (0, pg_core_1.integer)('upload_count').notNull().default(0),
    expiresAt: (0, pg_core_1.timestamp)('expires_at', { withTimezone: true }),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    codeIdx: (0, pg_core_1.index)('idx_upload_invites_code').on(table.code),
    statusIdx: (0, pg_core_1.index)('idx_upload_invites_status').on(table.status),
    createdByIdx: (0, pg_core_1.index)('idx_upload_invites_created_by').on(table.createdBy),
}));
// ============================================
// Tag System Tables
// ============================================
exports.tagCategories = (0, pg_core_1.pgTable)('tag_categories', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    name: (0, pg_core_1.text)('name').notNull().unique(),
    displayOrder: (0, pg_core_1.integer)('display_order').notNull().default(0),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    displayOrderIdx: (0, pg_core_1.index)('idx_tag_categories_display_order').on(table.displayOrder),
}));
exports.tags = (0, pg_core_1.pgTable)('tags', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    categoryId: (0, pg_core_1.integer)('category_id').notNull(),
    name: (0, pg_core_1.text)('name').notNull(),
    displayOrder: (0, pg_core_1.integer)('display_order').notNull().default(0),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    categoryIdx: (0, pg_core_1.index)('idx_tags_category').on(table.categoryId),
    displayOrderIdx: (0, pg_core_1.index)('idx_tags_display_order').on(table.displayOrder),
    uniqueNamePerCategory: (0, pg_core_1.index)('idx_tags_unique_name').on(table.categoryId, table.name),
}));
exports.publicMediaTags = (0, pg_core_1.pgTable)('public_media_tags', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    tagId: (0, pg_core_1.integer)('tag_id').notNull(),
    addedAt: (0, pg_core_1.timestamp)('added_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    mediaIdx: (0, pg_core_1.index)('idx_public_media_tags_media').on(table.mediaId),
    tagIdx: (0, pg_core_1.index)('idx_public_media_tags_tag').on(table.tagId),
    uniqueIdx: (0, pg_core_1.index)('idx_public_media_tags_unique').on(table.mediaId, table.tagId),
}));
exports.userUploadSuggestedTags = (0, pg_core_1.pgTable)('user_upload_suggested_tags', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    uploadId: (0, pg_core_1.integer)('upload_id').notNull(),
    tagId: (0, pg_core_1.integer)('tag_id').notNull(),
    suggestedAt: (0, pg_core_1.timestamp)('suggested_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    uploadIdx: (0, pg_core_1.index)('idx_user_upload_suggested_tags_upload').on(table.uploadId),
    tagIdx: (0, pg_core_1.index)('idx_user_upload_suggested_tags_tag').on(table.tagId),
    uniqueIdx: (0, pg_core_1.index)('idx_user_upload_suggested_tags_unique').on(table.uploadId, table.tagId),
}));
exports.userTagPreferences = (0, pg_core_1.pgTable)('user_tag_preferences', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull(),
    tagId: (0, pg_core_1.integer)('tag_id').notNull(),
    savedAt: (0, pg_core_1.timestamp)('saved_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_user_tag_preferences_user').on(table.userId),
    tagIdx: (0, pg_core_1.index)('idx_user_tag_preferences_tag').on(table.tagId),
    uniqueIdx: (0, pg_core_1.index)('idx_user_tag_preferences_unique').on(table.userId, table.tagId),
}));
// ============================================
// Public Media Performers Junction
// ============================================
/**
 * Links public media items to performers for "Browse Actors" feature.
 */
exports.publicMediaPerformers = (0, pg_core_1.pgTable)('public_media_performers', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    mediaId: (0, pg_core_1.integer)('media_id').notNull(),
    performerId: (0, pg_core_1.integer)('performer_id').notNull(),
    addedAt: (0, pg_core_1.timestamp)('added_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    mediaIdx: (0, pg_core_1.index)('idx_public_media_performers_media').on(table.mediaId),
    performerIdx: (0, pg_core_1.index)('idx_public_media_performers_performer').on(table.performerId),
    uniqueIdx: (0, pg_core_1.uniqueIndex)('idx_public_media_performers_unique').on(table.mediaId, table.performerId),
}));
// ============================================
// Video Digest Tables
// ============================================
exports.DIGEST_STATUS = [
    'pending', 'scene_detection', 'extracting', 'analyzing',
    'face_detection', 'transcribing', 'segmenting', 'synthesizing',
    'completed', 'failed', 'cancelled'
];
exports.videoDigests = (0, pg_core_1.pgTable)('video_digests', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    jobId: (0, pg_core_1.integer)('job_id'),
    status: (0, pg_core_1.text)('status').notNull().default('pending'),
    progress: (0, pg_core_1.integer)('progress').default(0),
    frameCount: (0, pg_core_1.integer)('frame_count'),
    config: (0, pg_core_1.jsonb)('config').$type(),
    frameAnalyses: (0, pg_core_1.jsonb)('frame_analyses').$type(),
    transcript: (0, pg_core_1.jsonb)('transcript').$type(),
    tags: (0, pg_core_1.jsonb)('tags').$type(),
    suggestedClips: (0, pg_core_1.jsonb)('suggested_clips').$type(),
    adCutSpec: (0, pg_core_1.jsonb)('ad_cut_spec').$type(),
    // Per-frame stage results for observability (persisted during analysis)
    stageResults: (0, pg_core_1.jsonb)('stage_results').$type(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    startedAt: (0, pg_core_1.timestamp)('started_at', { withTimezone: true }),
    completedAt: (0, pg_core_1.timestamp)('completed_at', { withTimezone: true }),
    error: (0, pg_core_1.text)('error'),
}, (table) => ({
    videoIdx: (0, pg_core_1.index)('idx_video_digests_video').on(table.videoId),
    statusIdx: (0, pg_core_1.index)('idx_video_digests_status').on(table.status),
    createdAtIdx: (0, pg_core_1.index)('idx_video_digests_created').on(table.createdAt),
}));
exports.digestVideoTags = (0, pg_core_1.pgTable)('digest_video_tags', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    category: (0, pg_core_1.text)('category').notNull(),
    value: (0, pg_core_1.text)('value').notNull(),
    confidence: (0, pg_core_1.integer)('confidence'),
    source: (0, pg_core_1.text)('source').default('digest'),
    evidence: (0, pg_core_1.jsonb)('evidence').$type(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    digestIdx: (0, pg_core_1.index)('idx_digest_video_tags_digest').on(table.digestId),
    videoIdx: (0, pg_core_1.index)('idx_digest_video_tags_video').on(table.videoId),
    categoryIdx: (0, pg_core_1.index)('idx_digest_video_tags_category').on(table.category),
    valueIdx: (0, pg_core_1.index)('idx_digest_video_tags_value').on(table.value),
    categoryValueIdx: (0, pg_core_1.index)('idx_digest_video_tags_cat_val').on(table.category, table.value),
}));
// ============================================
// Digest Clip Selection & Generation Tables
// ============================================
exports.CLIP_TYPES = ['hook', 'intro', 'action', 'climax', 'highlight'];
exports.CLIP_STATUS = ['pending', 'processing', 'completed', 'failed'];
exports.CLIP_SOURCES = ['machine', 'manual'];
// Stage 1: Selected clips from digest analysis (metadata only, no extraction yet)
exports.digestSelectedClips = (0, pg_core_1.pgTable)('digest_selected_clips', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    clipType: (0, pg_core_1.text)('clip_type').notNull(),
    startTime: (0, pg_core_1.integer)('start_time').notNull(), // seconds
    endTime: (0, pg_core_1.integer)('end_time').notNull(),
    duration: (0, pg_core_1.integer)('duration').notNull(),
    reason: (0, pg_core_1.text)('reason'),
    interestScore: (0, pg_core_1.integer)('interest_score'),
    position: (0, pg_core_1.text)('position'), // For action clips (e.g., 'doggy style')
    transcriptHint: (0, pg_core_1.text)('transcript_hint'), // For climax clips (keyword that triggered selection)
    tags: (0, pg_core_1.jsonb)('tags').$type(),
    source: (0, pg_core_1.text)('source').notNull().default('machine'),
    isIncluded: (0, pg_core_1.integer)('is_included').notNull().default(1), // 1 = included in generation, 0 = excluded
    isHook: (0, pg_core_1.integer)('is_hook').notNull().default(0), // 1 = this clip is the cinematic hook (teaser at start)
    sequenceOrder: (0, pg_core_1.integer)('sequence_order').notNull().default(0), // Order in final compilation (0-based)
    hookSourceClipId: (0, pg_core_1.integer)('hook_source_clip_id'), // If set, this is a hook copy cloned from the referenced clip
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    digestIdx: (0, pg_core_1.index)('idx_digest_selected_clips_digest').on(table.digestId),
    videoIdx: (0, pg_core_1.index)('idx_digest_selected_clips_video').on(table.videoId),
    clipTypeIdx: (0, pg_core_1.index)('idx_digest_selected_clips_type').on(table.clipType),
    sourceIdx: (0, pg_core_1.index)('idx_digest_selected_clips_source').on(table.source),
    sequenceOrderIdx: (0, pg_core_1.index)('idx_digest_selected_clips_sequence').on(table.sequenceOrder),
    isHookIdx: (0, pg_core_1.index)('idx_digest_selected_clips_is_hook').on(table.isHook),
    hookSourceIdx: (0, pg_core_1.index)('idx_digest_selected_clips_hook_source').on(table.hookSourceClipId),
}));
// Stage 2: Generated clips (after FFmpeg extraction)
exports.digestGeneratedClips = (0, pg_core_1.pgTable)('digest_generated_clips', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    selectedClipId: (0, pg_core_1.integer)('selected_clip_id').notNull(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    folderId: (0, pg_core_1.integer)('folder_id'), // References digestOutputFolders.id
    clipPath: (0, pg_core_1.text)('clip_path'),
    gifPath: (0, pg_core_1.text)('gif_path'), // Only set if duration <= 60s
    status: (0, pg_core_1.text)('status').notNull().default('pending'),
    error: (0, pg_core_1.text)('error'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    completedAt: (0, pg_core_1.timestamp)('completed_at', { withTimezone: true }),
    // Publishing tracking
    publishedToPublicMediaId: (0, pg_core_1.integer)('published_to_public_media_id'),
    publishedAt: (0, pg_core_1.timestamp)('published_at', { withTimezone: true }),
}, (table) => ({
    selectedClipIdx: (0, pg_core_1.index)('idx_digest_generated_clips_selected').on(table.selectedClipId),
    digestIdx: (0, pg_core_1.index)('idx_digest_generated_clips_digest').on(table.digestId),
    statusIdx: (0, pg_core_1.index)('idx_digest_generated_clips_status').on(table.status),
    folderIdx: (0, pg_core_1.index)('idx_digest_generated_clips_folder').on(table.folderId),
}));
// Caption style type for digest compilations
exports.CAPTION_POSITIONS = ['bottom', 'top'];
exports.CAPTION_SIZES = ['small', 'medium', 'large'];
// Stage 2: Compilation videos
exports.digestCompilations = (0, pg_core_1.pgTable)('digest_compilations', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    folderId: (0, pg_core_1.integer)('folder_id'), // References digestOutputFolders.id
    filename: (0, pg_core_1.text)('filename').notNull(),
    name: (0, pg_core_1.text)('name'), // Optional user-provided name for the compilation
    path: (0, pg_core_1.text)('path').notNull(),
    durationSeconds: (0, pg_core_1.integer)('duration_seconds'),
    orientation: (0, pg_core_1.text)('orientation'),
    status: (0, pg_core_1.text)('status').notNull().default('pending'),
    error: (0, pg_core_1.text)('error'),
    // Caption burning options
    hasCaptions: (0, pg_core_1.integer)('has_captions').notNull().default(0), // 1 = captions burned in
    captionStyle: (0, pg_core_1.jsonb)('caption_style').$type(),
    // Closing ad frame options
    closingAdPath: (0, pg_core_1.text)('closing_ad_path'), // Path to uploaded ad frame image
    closingAdDuration: (0, pg_core_1.integer)('closing_ad_duration'), // Duration in seconds (3-10)
    // Aggregated tags from constituent segments
    tags: (0, pg_core_1.jsonb)('tags').$type(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    completedAt: (0, pg_core_1.timestamp)('completed_at', { withTimezone: true }),
}, (table) => ({
    digestIdx: (0, pg_core_1.index)('idx_digest_compilations_digest').on(table.digestId),
    videoIdx: (0, pg_core_1.index)('idx_digest_compilations_video').on(table.videoId),
    statusIdx: (0, pg_core_1.index)('idx_digest_compilations_status').on(table.status),
    folderIdx: (0, pg_core_1.index)('idx_digest_compilations_folder').on(table.folderId),
}));
// ============================================
// Digest Output Folders Table
// ============================================
exports.digestOutputFolders = (0, pg_core_1.pgTable)('digest_output_folders', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    folderPath: (0, pg_core_1.text)('folder_path').notNull(),
    folderName: (0, pg_core_1.text)('folder_name').notNull(),
    folderType: (0, pg_core_1.text)('folder_type').notNull().default('clips'), // 'clips' | 'scenes' | 'compilation'
    clipCount: (0, pg_core_1.integer)('clip_count').default(0),
    compilationCount: (0, pg_core_1.integer)('compilation_count').default(0),
    totalSize: (0, pg_core_1.integer)('total_size'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    digestIdx: (0, pg_core_1.index)('idx_digest_output_folders_digest').on(table.digestId),
    videoIdx: (0, pg_core_1.index)('idx_digest_output_folders_video').on(table.videoId),
    folderPathIdx: (0, pg_core_1.index)('idx_digest_output_folders_path').on(table.folderPath),
}));
// ============================================
// Digest Generated Scenes Table
// ============================================
// Tracks individual scene files extracted from digests with derived tags
exports.digestGeneratedScenes = (0, pg_core_1.pgTable)('digest_generated_scenes', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    folderId: (0, pg_core_1.integer)('folder_id'), // References digestOutputFolders.id
    sceneNumber: (0, pg_core_1.integer)('scene_number').notNull(),
    scenePath: (0, pg_core_1.text)('scene_path'),
    startTime: (0, pg_core_1.real)('start_time').notNull(),
    endTime: (0, pg_core_1.real)('end_time').notNull(),
    duration: (0, pg_core_1.real)('duration').notNull(),
    // Tags derived from videoTagTimeline for this time range
    tags: (0, pg_core_1.jsonb)('tags').$type(),
    dominantPosition: (0, pg_core_1.text)('dominant_position'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    // Publishing tracking
    publishedToPublicMediaId: (0, pg_core_1.integer)('published_to_public_media_id'),
    publishedAt: (0, pg_core_1.timestamp)('published_at', { withTimezone: true }),
}, (table) => ({
    digestIdx: (0, pg_core_1.index)('idx_digest_generated_scenes_digest').on(table.digestId),
    videoIdx: (0, pg_core_1.index)('idx_digest_generated_scenes_video').on(table.videoId),
    folderIdx: (0, pg_core_1.index)('idx_digest_generated_scenes_folder').on(table.folderId),
    scenePathIdx: (0, pg_core_1.index)('idx_digest_generated_scenes_path').on(table.scenePath),
}));
// Caches detected scene cuts per video for clean clip transitions
// Extended for combined multi-detector scene detection
exports.videoSceneCuts = (0, pg_core_1.pgTable)('video_scene_cuts', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    // Array of cut timestamps in seconds (includes 0 and video end)
    cuts: (0, pg_core_1.jsonb)('cuts').$type().notNull(),
    // Number of scenes detected
    sceneCount: (0, pg_core_1.integer)('scene_count').notNull(),
    // Video duration at time of detection
    duration: (0, pg_core_1.real)('duration').notNull(),
    // Detection configuration
    detector: (0, pg_core_1.text)('detector').notNull().default('content'), // 'content', 'adaptive', 'transnetv2', 'combined'
    threshold: (0, pg_core_1.real)('threshold').notNull().default(27.0),
    // ============================================
    // Combined Detection Fields (for multi-detector merging)
    // ============================================
    // Individual detector results for debugging/analysis
    transnetCuts: (0, pg_core_1.jsonb)('transnet_cuts').$type(),
    pyscenedetectCuts: (0, pg_core_1.jsonb)('pyscenedetect_cuts').$type(),
    clipCuts: (0, pg_core_1.jsonb)('clip_cuts').$type(),
    // Detailed merged cuts with source attribution
    mergedCutsDetailed: (0, pg_core_1.jsonb)('merged_cuts_detailed').$type(),
    // Merge configuration
    mergeStrategy: (0, pg_core_1.text)('merge_strategy').default('weighted'), // 'union' | 'intersection' | 'weighted' | 'majority'
    toleranceSeconds: (0, pg_core_1.real)('tolerance_seconds').default(0.75),
    // Which detectors were used (for cache validation)
    detectorsUsed: (0, pg_core_1.jsonb)('detectors_used').$type(),
    // Total processing time for combined detection
    processingTimeMs: (0, pg_core_1.integer)('processing_time_ms'),
    // Timestamps
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    videoIdx: (0, pg_core_1.index)('idx_video_scene_cuts_video').on(table.videoId),
}));
// ============================================
// Video Segmentation Tables (Multi-Method Analysis)
// ============================================
// Segment types for multi-method clip detection
exports.SEGMENT_TYPES = ['scene', 'tag_change', 'vocal', 'fixed_interval'];
// Vocal moment categories for transcript-based segments
exports.VOCAL_CATEGORIES = ['dialogue', 'dirty_talk', 'climax', 'interview', 'moan'];
// Stores JoyTag results at regular intervals for change detection
exports.videoTagTimeline = (0, pg_core_1.pgTable)('video_tag_timeline', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    timestamp: (0, pg_core_1.real)('timestamp').notNull(), // Seconds from video start
    // JoyTag results at this timestamp
    tags: (0, pg_core_1.jsonb)('tags').$type().notNull(),
    // Derived/computed fields for efficient querying
    dominantPosition: (0, pg_core_1.text)('dominant_position'), // Most confident sexual position tag
    performerCount: (0, pg_core_1.integer)('performer_count'),
    intensity: (0, pg_core_1.integer)('intensity'), // 0-10 score based on tag analysis
    hasDialogue: (0, pg_core_1.boolean)('has_dialogue').default(false),
    hasEyeContact: (0, pg_core_1.boolean)('has_eye_contact').default(false),
    // Frame reference
    framePath: (0, pg_core_1.text)('frame_path'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    videoIdx: (0, pg_core_1.index)('idx_video_tag_timeline_video').on(table.videoId),
    digestIdx: (0, pg_core_1.index)('idx_video_tag_timeline_digest').on(table.digestId),
    timestampIdx: (0, pg_core_1.index)('idx_video_tag_timeline_timestamp').on(table.videoId, table.timestamp),
    positionIdx: (0, pg_core_1.index)('idx_video_tag_timeline_position').on(table.dominantPosition),
}));
// Stores detected segments by type (scene, tag_change, vocal, fixed_interval)
exports.videoSegments = (0, pg_core_1.pgTable)('video_segments', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    segmentType: (0, pg_core_1.text)('segment_type').notNull().$type(),
    startTime: (0, pg_core_1.real)('start_time').notNull(), // Seconds
    endTime: (0, pg_core_1.real)('end_time').notNull(), // Seconds
    duration: (0, pg_core_1.real)('duration').notNull(), // Seconds
    // Segment metadata (varies by type)
    tags: (0, pg_core_1.jsonb)('tags').$type(),
    transcriptSnippet: (0, pg_core_1.text)('transcript_snippet'),
    vocalCategory: (0, pg_core_1.text)('vocal_category').$type(),
    positionChange: (0, pg_core_1.text)('position_change'), // "oral → doggystyle"
    dominantPosition: (0, pg_core_1.text)('dominant_position'),
    // Scoring for auto-sequence building
    interestScore: (0, pg_core_1.real)('interest_score').default(0),
    hasEyeContact: (0, pg_core_1.boolean)('has_eye_contact').default(false),
    hasFullSentence: (0, pg_core_1.boolean)('has_full_sentence').default(false),
    isClimaxMoment: (0, pg_core_1.boolean)('is_climax_moment').default(false),
    // Caption/title generation
    captioned: (0, pg_core_1.boolean)('captioned').default(false),
    captionText: (0, pg_core_1.text)('caption_text'),
    title: (0, pg_core_1.text)('title'),
    // Frame reference for thumbnail
    keyframePath: (0, pg_core_1.text)('keyframe_path'),
    keyframeTimestamp: (0, pg_core_1.real)('keyframe_timestamp'),
    // Inclusion in sequence (for Abstract)
    isIncluded: (0, pg_core_1.boolean)('is_included').default(true),
    sequenceOrder: (0, pg_core_1.integer)('sequence_order'),
    isHook: (0, pg_core_1.boolean)('is_hook').default(false),
    // Inclusion for clip generation (for Clips tab, independent from Abstract)
    includeInClips: (0, pg_core_1.boolean)('include_in_clips').default(true),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    digestIdx: (0, pg_core_1.index)('idx_video_segments_digest').on(table.digestId),
    videoIdx: (0, pg_core_1.index)('idx_video_segments_video').on(table.videoId),
    typeIdx: (0, pg_core_1.index)('idx_video_segments_type').on(table.segmentType),
    timeIdx: (0, pg_core_1.index)('idx_video_segments_time').on(table.videoId, table.startTime),
    includedIdx: (0, pg_core_1.index)('idx_video_segments_included').on(table.digestId, table.isIncluded),
    sequenceIdx: (0, pg_core_1.index)('idx_video_segments_sequence').on(table.digestId, table.sequenceOrder),
    clipsIdx: (0, pg_core_1.index)('idx_video_segments_clips').on(table.digestId, table.includeInClips),
}));
// ============================================
// Video Tag Mapping Tables (Digest → Tag System)
// ============================================
// Links videos to existing tags (from digest or manual)
exports.videoTags = (0, pg_core_1.pgTable)('video_tags', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    tagId: (0, pg_core_1.integer)('tag_id').notNull(),
    confidence: (0, pg_core_1.integer)('confidence'), // 0-100, null for manual
    source: (0, pg_core_1.text)('source').notNull().default('manual'),
    digestId: (0, pg_core_1.integer)('digest_id'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    videoIdx: (0, pg_core_1.index)('idx_video_tags_video').on(table.videoId),
    tagIdx: (0, pg_core_1.index)('idx_video_tags_tag').on(table.tagId),
    sourceIdx: (0, pg_core_1.index)('idx_video_tags_source').on(table.source),
    uniqueIdx: (0, pg_core_1.index)('idx_video_tags_unique').on(table.videoId, table.tagId),
}));
exports.SUGGESTED_TAG_STATUS = ['pending', 'approved', 'rejected', 'mapped'];
// Unmatched tags from digest that need admin review
exports.digestSuggestedTags = (0, pg_core_1.pgTable)('digest_suggested_tags', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    suggestedCategory: (0, pg_core_1.text)('suggested_category').notNull(),
    suggestedValue: (0, pg_core_1.text)('suggested_value').notNull(),
    confidence: (0, pg_core_1.integer)('confidence'), // 0-100
    status: (0, pg_core_1.text)('status').notNull().default('pending'),
    mappedTagId: (0, pg_core_1.integer)('mapped_tag_id'),
    reviewedBy: (0, pg_core_1.integer)('reviewed_by'),
    reviewedAt: (0, pg_core_1.timestamp)('reviewed_at', { withTimezone: true }),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    digestIdx: (0, pg_core_1.index)('idx_digest_suggested_tags_digest').on(table.digestId),
    videoIdx: (0, pg_core_1.index)('idx_digest_suggested_tags_video').on(table.videoId),
    statusIdx: (0, pg_core_1.index)('idx_digest_suggested_tags_status').on(table.status),
    categoryValueIdx: (0, pg_core_1.index)('idx_digest_suggested_tags_cat_val').on(table.suggestedCategory, table.suggestedValue),
}));
// Clip-level tag assignments (links clips to formal tags)
exports.digestClipTags = (0, pg_core_1.pgTable)('digest_clip_tags', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    clipId: (0, pg_core_1.integer)('clip_id').notNull(),
    tagId: (0, pg_core_1.integer)('tag_id').notNull(),
    source: (0, pg_core_1.text)('source').notNull().default('auto'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    clipIdx: (0, pg_core_1.index)('idx_digest_clip_tags_clip').on(table.clipId),
    tagIdx: (0, pg_core_1.index)('idx_digest_clip_tags_tag').on(table.tagId),
    uniqueIdx: (0, pg_core_1.index)('idx_digest_clip_tags_unique').on(table.clipId, table.tagId),
}));
// ============================================
// Watch Party Tables
// ============================================
exports.WATCH_PARTY_STATUS = ['waiting', 'active', 'paused', 'ended'];
exports.LOOP_MODE = ['none', 'video', 'queue'];
exports.watchPartySessions = (0, pg_core_1.pgTable)('watch_party_sessions', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    hostId: (0, pg_core_1.integer)('host_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    mediaId: (0, pg_core_1.integer)('media_id').notNull().references(() => exports.publicMedia.id, { onDelete: 'cascade' }),
    inviteCode: (0, pg_core_1.text)('invite_code').notNull().unique(),
    status: (0, pg_core_1.text)('status').notNull().default('waiting'),
    currentTime: (0, pg_core_1.integer)('current_time').default(0), // playback position in seconds
    isPlaying: (0, pg_core_1.boolean)('is_playing').default(false),
    maxParticipants: (0, pg_core_1.integer)('max_participants').default(20),
    allowChat: (0, pg_core_1.boolean)('allow_chat').default(true),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    startedAt: (0, pg_core_1.timestamp)('started_at', { withTimezone: true }),
    endedAt: (0, pg_core_1.timestamp)('ended_at', { withTimezone: true }),
    // Post-party summary stats (generated when party ends)
    summaryStats: (0, pg_core_1.jsonb)('summary_stats').$type(),
}, (table) => ({
    hostIdx: (0, pg_core_1.index)('idx_watch_party_sessions_host').on(table.hostId),
    inviteCodeIdx: (0, pg_core_1.index)('idx_watch_party_sessions_invite').on(table.inviteCode),
    statusIdx: (0, pg_core_1.index)('idx_watch_party_sessions_status').on(table.status),
    createdAtIdx: (0, pg_core_1.index)('idx_watch_party_sessions_created').on(table.createdAt),
}));
exports.watchPartyParticipants = (0, pg_core_1.pgTable)('watch_party_participants', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    partyId: (0, pg_core_1.integer)('party_id').notNull().references(() => exports.watchPartySessions.id, { onDelete: 'cascade' }),
    userId: (0, pg_core_1.integer)('user_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    isConnected: (0, pg_core_1.boolean)('is_connected').default(false),
    isKicked: (0, pg_core_1.boolean)('is_kicked').default(false),
    joinedAt: (0, pg_core_1.timestamp)('joined_at', { withTimezone: true }).defaultNow(),
    leftAt: (0, pg_core_1.timestamp)('left_at', { withTimezone: true }),
}, (table) => ({
    partyIdx: (0, pg_core_1.index)('idx_watch_party_participants_party').on(table.partyId),
    userIdx: (0, pg_core_1.index)('idx_watch_party_participants_user').on(table.userId),
    uniqueIdx: (0, pg_core_1.index)('idx_watch_party_participants_unique').on(table.partyId, table.userId),
}));
exports.watchPartyChatMessages = (0, pg_core_1.pgTable)('watch_party_chat_messages', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    partyId: (0, pg_core_1.integer)('party_id').notNull().references(() => exports.watchPartySessions.id, { onDelete: 'cascade' }),
    userId: (0, pg_core_1.integer)('user_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    content: (0, pg_core_1.text)('content').notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    partyIdx: (0, pg_core_1.index)('idx_watch_party_chat_party').on(table.partyId),
    createdAtIdx: (0, pg_core_1.index)('idx_watch_party_chat_created').on(table.createdAt),
}));
// Watch Party Reactions (persisted for summary stats)
exports.watchPartyReactions = (0, pg_core_1.pgTable)('watch_party_reactions', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    partyId: (0, pg_core_1.integer)('party_id').notNull().references(() => exports.watchPartySessions.id, { onDelete: 'cascade' }),
    userId: (0, pg_core_1.integer)('user_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    reactionType: (0, pg_core_1.text)('reaction_type').notNull(),
    videoTimestamp: (0, pg_core_1.integer)('video_timestamp'), // seconds into video when reaction was sent
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    partyIdx: (0, pg_core_1.index)('idx_watch_party_reactions_party').on(table.partyId),
    userIdx: (0, pg_core_1.index)('idx_watch_party_reactions_user').on(table.userId),
}));
// Watch Party Invites
exports.INVITE_STATUS = ['pending', 'accepted', 'declined', 'expired'];
exports.watchPartyInvites = (0, pg_core_1.pgTable)('watch_party_invites', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    partyId: (0, pg_core_1.integer)('party_id').notNull().references(() => exports.watchPartySessions.id, { onDelete: 'cascade' }),
    fromUserId: (0, pg_core_1.integer)('from_user_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    toUserId: (0, pg_core_1.integer)('to_user_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    status: (0, pg_core_1.text)('status').notNull().default('pending').$type(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    respondedAt: (0, pg_core_1.timestamp)('responded_at', { withTimezone: true }),
}, (table) => ({
    partyIdx: (0, pg_core_1.index)('idx_watch_party_invites_party').on(table.partyId),
    toUserIdx: (0, pg_core_1.index)('idx_watch_party_invites_to_user').on(table.toUserId),
    fromUserIdx: (0, pg_core_1.index)('idx_watch_party_invites_from_user').on(table.fromUserId),
    statusIdx: (0, pg_core_1.index)('idx_watch_party_invites_status').on(table.status),
}));
exports.tagGenerationJobs = (0, pg_core_1.pgTable)('tag_generation_jobs', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    status: (0, pg_core_1.text)('status').$type().default('pending').notNull(),
    contentType: (0, pg_core_1.text)('content_type').$type().notNull(),
    contentIds: (0, pg_core_1.jsonb)('content_ids').$type().notNull(),
    options: (0, pg_core_1.jsonb)('options').$type(),
    results: (0, pg_core_1.jsonb)('results').$type(),
    progress: (0, pg_core_1.integer)('progress').default(0),
    currentItem: (0, pg_core_1.integer)('current_item').default(0),
    totalItems: (0, pg_core_1.integer)('total_items').default(0),
    error: (0, pg_core_1.text)('error'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    completedAt: (0, pg_core_1.timestamp)('completed_at', { withTimezone: true }),
}, (table) => ({
    statusIdx: (0, pg_core_1.index)('idx_tag_gen_status').on(table.status),
    contentTypeIdx: (0, pg_core_1.index)('idx_tag_gen_content_type').on(table.contentType),
    createdAtIdx: (0, pg_core_1.index)('idx_tag_gen_created_at').on(table.createdAt),
}));
// ============================================================================
// Performer Face Recognition
// ============================================================================
/**
 * Named performers that can be associated with multiple detected faces.
 * Integrates with tag system for public gallery filtering.
 */
exports.creators = (0, pg_core_1.pgTable)('creators', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    name: (0, pg_core_1.text)('name').notNull().unique(),
    slug: (0, pg_core_1.text)('slug').notNull().unique(), // URL-friendly name for public browsing
    gender: (0, pg_core_1.integer)('gender'), // 0=female, 1=male, null=unknown
    primaryFaceId: (0, pg_core_1.integer)('primary_face_id'), // Best face image for display thumbnail
    faceCount: (0, pg_core_1.integer)('face_count').default(0), // Denormalized count of linked faces
    videoCount: (0, pg_core_1.integer)('video_count').default(0), // Videos featuring this performer
    tagId: (0, pg_core_1.integer)('tag_id'), // Link to performers tag category for filtering
    isPublic: (0, pg_core_1.boolean)('is_public').default(false), // Visible in public Browse Actors
    // Centroid embedding for efficient matching (512-D averaged, quality-filtered)
    centroidEmbedding: (0, pg_core_1.jsonb)('centroid_embedding').$type(),
    centroidUpdatedAt: (0, pg_core_1.timestamp)('centroid_updated_at', { withTimezone: true }),
    centroidFaceCount: (0, pg_core_1.integer)('centroid_face_count').default(0), // Faces used in centroid computation
    // Quality metrics for adaptive matching
    embeddingVariance: (0, pg_core_1.real)('embedding_variance'), // How spread out the embeddings are
    avgIntraClusterSimilarity: (0, pg_core_1.real)('avg_intra_cluster_similarity'), // Average similarity within performer's faces
    avgAge: (0, pg_core_1.real)('avg_age'), // Average detected age of performer
    ageStdDev: (0, pg_core_1.real)('age_std_dev'), // Standard deviation of detected ages
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    nameIdx: (0, pg_core_1.index)('idx_creators_name').on(table.name),
    slugIdx: (0, pg_core_1.index)('idx_creators_slug').on(table.slug),
    genderIdx: (0, pg_core_1.index)('idx_creators_gender').on(table.gender),
    tagIdx: (0, pg_core_1.index)('idx_creators_tag').on(table.tagId),
    publicIdx: (0, pg_core_1.index)('idx_creators_public').on(table.isPublic),
}));
// Face status for tracking review state
exports.FACE_STATUS = ['pending', 'assigned', 'ignored', 'skipped'];
/**
 * Stores face embeddings for performer recognition.
 * Each row represents a single detected face that can be linked to a performer.
 */
exports.performerFaces = (0, pg_core_1.pgTable)('performer_faces', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    // Performer identification - FK to performers table (null if unidentified)
    performerId: (0, pg_core_1.integer)('performer_id'), // Links to creators.id
    performerName: (0, pg_core_1.text)('performer_name'), // Legacy field, kept for migration
    // 512-dimensional face embedding vector from ArcFace
    // Stored as JSON array for compatibility (consider pgvector for production)
    faceEmbedding: (0, pg_core_1.jsonb)('face_embedding').$type().notNull(),
    // Face attributes from InsightFace
    gender: (0, pg_core_1.integer)('gender'), // 0=female, 1=male
    age: (0, pg_core_1.integer)('age'),
    detectionScore: (0, pg_core_1.real)('detection_score'), // Confidence of face detection
    // Bounding box in source frame [x1, y1, x2, y2]
    bbox: (0, pg_core_1.jsonb)('bbox').$type(),
    // Face crop image path
    faceCropPath: (0, pg_core_1.text)('face_crop_path'), // Path to cropped face thumbnail
    // Source information
    sourceFrame: (0, pg_core_1.text)('source_frame'), // Path to frame this was extracted from
    sourceVideo: (0, pg_core_1.text)('source_video'), // Path to source video
    sourceDigestId: (0, pg_core_1.integer)('source_digest_id'), // Link to video digest
    frameTimestamp: (0, pg_core_1.real)('frame_timestamp'), // Timestamp in video
    frameIndex: (0, pg_core_1.integer)('frame_index'), // Index of frame in digest
    // Face grouping metadata
    facesInFrame: (0, pg_core_1.integer)('faces_in_frame').default(1), // How many faces were in this frame
    status: (0, pg_core_1.text)('status').$type().default('pending'), // Review status
    // Matching metadata
    matchConfidence: (0, pg_core_1.real)('match_confidence'), // Confidence of performer match (if matched)
    isVerified: (0, pg_core_1.boolean)('is_verified').default(false), // Human-verified match
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    performerIdIdx: (0, pg_core_1.index)('idx_performer_faces_performer').on(table.performerId),
    performerNameIdx: (0, pg_core_1.index)('idx_performer_faces_name').on(table.performerName),
    sourceVideoIdx: (0, pg_core_1.index)('idx_performer_faces_video').on(table.sourceVideo),
    genderIdx: (0, pg_core_1.index)('idx_performer_faces_gender').on(table.gender),
    digestIdx: (0, pg_core_1.index)('idx_performer_faces_digest').on(table.sourceDigestId),
    cropPathIdx: (0, pg_core_1.index)('idx_performer_faces_crop').on(table.faceCropPath),
    statusIdx: (0, pg_core_1.index)('idx_performer_faces_status').on(table.status),
    facesInFrameIdx: (0, pg_core_1.index)('idx_performer_faces_faces_in_frame').on(table.facesInFrame),
    detectionScoreIdx: (0, pg_core_1.index)('idx_performer_faces_det_score').on(table.detectionScore),
}));
// Discrepancy types for filename vs face detection mismatches
exports.DISCREPANCY_TYPES = [
    'no_face_match', // Parsed name has no matching face
    'low_confidence', // Face match confidence below threshold
    'name_mismatch', // Filename says X but face matches Y
    'gender_mismatch', // Gender of face doesn't match expected
    'unknown_performer', // Parsed name not in performers database
    'extra_face', // Detected face not in parsed performers
];
// Resolution status for discrepancies
exports.DISCREPANCY_STATUS = ['pending', 'confirmed', 'rejected', 'merged', 'ignored'];
// Resolution types
exports.DISCREPANCY_RESOLUTIONS = ['use_filename', 'use_face', 'create_alias', 'ignore', 'assign_face'];
/**
 * Tracks mismatches between filename-parsed performers and face detection results.
 * Used for admin review and resolution of performer identification issues.
 */
exports.performerDiscrepancies = (0, pg_core_1.pgTable)('performer_discrepancies', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    // Source info
    videoId: (0, pg_core_1.integer)('video_id').references(() => exports.videos.id, { onDelete: 'cascade' }),
    digestId: (0, pg_core_1.integer)('digest_id').references(() => exports.videoDigests.id, { onDelete: 'cascade' }),
    // What filename parsing said
    parsedPerformerName: (0, pg_core_1.text)('parsed_performer_name').notNull(),
    parsedMethod: (0, pg_core_1.text)('parsed_method'), // 'llm', 'regex', 'manual'
    parsedConfidence: (0, pg_core_1.real)('parsed_confidence'),
    // What face detection found
    detectedPerformerId: (0, pg_core_1.integer)('detected_performer_id').references(() => exports.creators.id, { onDelete: 'set null' }),
    detectedPerformerName: (0, pg_core_1.text)('detected_performer_name'),
    faceMatchConfidence: (0, pg_core_1.real)('face_match_confidence'),
    faceSimilarity: (0, pg_core_1.real)('face_similarity'),
    // Discrepancy details
    discrepancyType: (0, pg_core_1.text)('discrepancy_type').$type().notNull(),
    // Resolution
    status: (0, pg_core_1.text)('status').$type().default('pending').notNull(),
    resolvedBy: (0, pg_core_1.integer)('resolved_by').references(() => exports.mediaUsers.id, { onDelete: 'set null' }),
    resolvedAt: (0, pg_core_1.timestamp)('resolved_at', { withTimezone: true }),
    resolution: (0, pg_core_1.text)('resolution').$type(),
    adminNotes: (0, pg_core_1.text)('admin_notes'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow().notNull(),
}, (table) => ({
    videoIdx: (0, pg_core_1.index)('idx_discrepancies_video').on(table.videoId),
    digestIdx: (0, pg_core_1.index)('idx_discrepancies_digest').on(table.digestId),
    statusIdx: (0, pg_core_1.index)('idx_discrepancies_status').on(table.status),
    typeIdx: (0, pg_core_1.index)('idx_discrepancies_type').on(table.discrepancyType),
    detectedPerformerIdx: (0, pg_core_1.index)('idx_discrepancies_detected_performer').on(table.detectedPerformerId),
}));
// ============================================
// Pipeline Management System
// ============================================
// Pipeline status lifecycle
exports.PIPELINE_STATUS = ['pending', 'queued', 'running', 'paused', 'completed', 'failed', 'cancelled'];
// Pipeline step status
exports.PIPELINE_STEP_STATUS = ['pending', 'waiting_dependency', 'waiting_resource', 'running', 'completed', 'failed', 'skipped'];
// Pipeline definition - a multi-step workflow
exports.pipelines = (0, pg_core_1.pgTable)('pipelines', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    name: (0, pg_core_1.text)('name').notNull(),
    description: (0, pg_core_1.text)('description'),
    status: (0, pg_core_1.text)('status').notNull().default('pending').$type(),
    priority: (0, pg_core_1.integer)('priority').default(5),
    // Context for the entire pipeline (e.g., videoId, digestId)
    context: (0, pg_core_1.jsonb)('context').$type(),
    // Resource requirements aggregated from steps
    totalVramRequired: (0, pg_core_1.integer)('total_vram_required').default(0),
    estimatedDurationMs: (0, pg_core_1.integer)('estimated_duration_ms'),
    // Progress tracking
    progress: (0, pg_core_1.integer)('progress').default(0),
    currentStepId: (0, pg_core_1.integer)('current_step_id'),
    completedSteps: (0, pg_core_1.integer)('completed_steps').default(0),
    totalSteps: (0, pg_core_1.integer)('total_steps').default(0),
    // Error handling
    error: (0, pg_core_1.text)('error'),
    retryCount: (0, pg_core_1.integer)('retry_count').default(0),
    maxRetries: (0, pg_core_1.integer)('max_retries').default(3),
    // Timestamps
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    queuedAt: (0, pg_core_1.timestamp)('queued_at', { withTimezone: true }),
    startedAt: (0, pg_core_1.timestamp)('started_at', { withTimezone: true }),
    completedAt: (0, pg_core_1.timestamp)('completed_at', { withTimezone: true }),
    // Crash recovery
    lastHeartbeat: (0, pg_core_1.timestamp)('last_heartbeat', { withTimezone: true }),
    runningOnNode: (0, pg_core_1.text)('running_on_node'), // For future multi-node support
}, (table) => ({
    statusIdx: (0, pg_core_1.index)('idx_pipelines_status').on(table.status),
    priorityIdx: (0, pg_core_1.index)('idx_pipelines_priority').on(table.priority, table.createdAt),
    heartbeatIdx: (0, pg_core_1.index)('idx_pipelines_heartbeat').on(table.lastHeartbeat),
}));
// Individual steps within a pipeline
exports.pipelineSteps = (0, pg_core_1.pgTable)('pipeline_steps', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    pipelineId: (0, pg_core_1.integer)('pipeline_id').notNull().references(() => exports.pipelines.id, { onDelete: 'cascade' }),
    // Step definition
    name: (0, pg_core_1.text)('name').notNull(),
    stepType: (0, pg_core_1.text)('step_type').notNull().$type(),
    sequenceOrder: (0, pg_core_1.integer)('sequence_order').notNull(),
    // Dependencies (array of step IDs that must complete first)
    dependsOn: (0, pg_core_1.jsonb)('depends_on').$type().default([]),
    // Resource requirements
    resourceCategory: (0, pg_core_1.text)('resource_category').default('cpu').$type(),
    vramRequired: (0, pg_core_1.integer)('vram_required').default(0),
    requiredContainers: (0, pg_core_1.jsonb)('required_containers').$type().default([]),
    // Step configuration
    config: (0, pg_core_1.jsonb)('config').$type(),
    // Execution state
    status: (0, pg_core_1.text)('status').notNull().default('pending').$type(),
    progress: (0, pg_core_1.integer)('progress').default(0),
    result: (0, pg_core_1.jsonb)('result').$type(),
    error: (0, pg_core_1.text)('error'),
    // Timing
    estimatedDurationMs: (0, pg_core_1.integer)('estimated_duration_ms'),
    startedAt: (0, pg_core_1.timestamp)('started_at', { withTimezone: true }),
    completedAt: (0, pg_core_1.timestamp)('completed_at', { withTimezone: true }),
    durationMs: (0, pg_core_1.integer)('duration_ms'),
}, (table) => ({
    pipelineIdx: (0, pg_core_1.index)('idx_pipeline_steps_pipeline').on(table.pipelineId),
    sequenceIdx: (0, pg_core_1.index)('idx_pipeline_steps_sequence').on(table.pipelineId, table.sequenceOrder),
    statusIdx: (0, pg_core_1.index)('idx_pipeline_steps_status').on(table.status),
}));
// Step-level progress events for detailed observability
exports.pipelineStepEvents = (0, pg_core_1.pgTable)('pipeline_step_events', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    stepId: (0, pg_core_1.integer)('step_id').notNull().references(() => exports.pipelineSteps.id, { onDelete: 'cascade' }),
    eventType: (0, pg_core_1.text)('event_type').notNull(), // 'stage_start', 'progress', 'prompt_call', 'stage_complete', 'log', 'error'
    eventData: (0, pg_core_1.jsonb)('event_data').$type(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    stepIdx: (0, pg_core_1.index)('idx_pipeline_step_events_step').on(table.stepId),
    createdAtIdx: (0, pg_core_1.index)('idx_pipeline_step_events_created').on(table.createdAt),
}));
// Real-time GPU/resource tracking snapshots
exports.resourceSnapshots = (0, pg_core_1.pgTable)('resource_snapshots', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    // GPU metrics (from nvidia-smi)
    gpuIndex: (0, pg_core_1.integer)('gpu_index').default(0),
    gpuName: (0, pg_core_1.text)('gpu_name'),
    vramUsedMb: (0, pg_core_1.integer)('vram_used_mb'),
    vramTotalMb: (0, pg_core_1.integer)('vram_total_mb'),
    gpuUtilization: (0, pg_core_1.integer)('gpu_utilization'), // 0-100%
    gpuTemperature: (0, pg_core_1.integer)('gpu_temperature'), // Celsius
    // Active processes using GPU
    activeProcesses: (0, pg_core_1.jsonb)('active_processes').$type(),
    // Linked to pipeline/step if applicable
    pipelineId: (0, pg_core_1.integer)('pipeline_id'),
    stepId: (0, pg_core_1.integer)('step_id'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    createdAtIdx: (0, pg_core_1.index)('idx_resource_snapshots_created').on(table.createdAt),
    pipelineIdx: (0, pg_core_1.index)('idx_resource_snapshots_pipeline').on(table.pipelineId),
}));
// Pipeline templates for common workflows
exports.pipelineTemplates = (0, pg_core_1.pgTable)('pipeline_templates', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    name: (0, pg_core_1.text)('name').notNull().unique(),
    displayName: (0, pg_core_1.text)('display_name').notNull(),
    description: (0, pg_core_1.text)('description'),
    // Template definition - array of step configurations
    steps: (0, pg_core_1.jsonb)('steps').$type().notNull(),
    // Default context schema (for validation)
    contextSchema: (0, pg_core_1.jsonb)('context_schema').$type(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }),
}, (table) => ({
    nameIdx: (0, pg_core_1.index)('idx_pipeline_templates_name').on(table.name),
}));
// Subscription Plans - Available subscription tiers
exports.subscriptionPlans = (0, pg_core_1.pgTable)('subscription_plans', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    name: (0, pg_core_1.text)('name').notNull().unique(), // 'monthly', 'quarterly', 'yearly', 'lifetime'
    displayName: (0, pg_core_1.text)('display_name').notNull(), // 'Monthly Subscription'
    description: (0, pg_core_1.text)('description'),
    priceCAD: (0, pg_core_1.integer)('price_cad').notNull(), // Price in cents (e.g., 1000 = $10.00)
    durationDays: (0, pg_core_1.integer)('duration_days'), // null for lifetime
    isActive: (0, pg_core_1.boolean)('is_active').default(true),
    sortOrder: (0, pg_core_1.integer)('sort_order').default(0),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }),
});
// User Subscriptions - Tracks individual user subscription status
exports.userSubscriptions = (0, pg_core_1.pgTable)('user_subscriptions', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    planId: (0, pg_core_1.integer)('plan_id').references(() => exports.subscriptionPlans.id),
    status: (0, pg_core_1.text)('status').notNull().default('inactive').$type(),
    startDate: (0, pg_core_1.timestamp)('start_date', { withTimezone: true }),
    endDate: (0, pg_core_1.timestamp)('end_date', { withTimezone: true }), // null for lifetime
    gracePeriodEndDate: (0, pg_core_1.timestamp)('grace_period_end_date', { withTimezone: true }),
    lastPaymentId: (0, pg_core_1.integer)('last_payment_id'),
    autoRenew: (0, pg_core_1.boolean)('auto_renew').default(true),
    notes: (0, pg_core_1.text)('notes'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }),
}, (table) => ({
    userIdx: (0, pg_core_1.uniqueIndex)('idx_user_subscriptions_user').on(table.userId),
    statusIdx: (0, pg_core_1.index)('idx_user_subscriptions_status').on(table.status),
    endDateIdx: (0, pg_core_1.index)('idx_user_subscriptions_end_date').on(table.endDate),
}));
// Invoices - Generated invoices for users
exports.invoices = (0, pg_core_1.pgTable)('invoices', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    planId: (0, pg_core_1.integer)('plan_id').references(() => exports.subscriptionPlans.id),
    invoiceNumber: (0, pg_core_1.text)('invoice_number').notNull().unique(), // INV-2026-00001
    amountCAD: (0, pg_core_1.integer)('amount_cad').notNull(), // Amount in cents
    status: (0, pg_core_1.text)('status').notNull().default('pending').$type(),
    dueDate: (0, pg_core_1.timestamp)('due_date', { withTimezone: true }).notNull(),
    paidAt: (0, pg_core_1.timestamp)('paid_at', { withTimezone: true }),
    paymentId: (0, pg_core_1.integer)('payment_id'),
    description: (0, pg_core_1.text)('description'),
    notes: (0, pg_core_1.text)('notes'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_invoices_user').on(table.userId),
    statusIdx: (0, pg_core_1.index)('idx_invoices_status').on(table.status),
    dueDateIdx: (0, pg_core_1.index)('idx_invoices_due_date').on(table.dueDate),
    invoiceNumberIdx: (0, pg_core_1.index)('idx_invoices_number').on(table.invoiceNumber),
}));
// Payments - Records of actual payments received (e-transfers)
exports.payments = (0, pg_core_1.pgTable)('payments', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    invoiceId: (0, pg_core_1.integer)('invoice_id').references(() => exports.invoices.id),
    userId: (0, pg_core_1.integer)('user_id').references(() => exports.mediaUsers.id, { onDelete: 'set null' }),
    // E-transfer details
    senderEmail: (0, pg_core_1.text)('sender_email').notNull(),
    senderName: (0, pg_core_1.text)('sender_name'),
    amountCAD: (0, pg_core_1.integer)('amount_cad').notNull(), // Amount in cents
    referenceNumber: (0, pg_core_1.text)('reference_number').unique(), // Interac reference
    customMessage: (0, pg_core_1.text)('custom_message'), // Contains username hint
    // Matching/processing status
    status: (0, pg_core_1.text)('status').notNull().default('unmatched').$type(),
    matchConfidence: (0, pg_core_1.real)('match_confidence'), // 0.0-1.0 confidence score
    matchMethod: (0, pg_core_1.text)('match_method'), // 'email_exact', 'username_message', 'manual', 'llm'
    // Raw email data for audit trail
    rawEmailJson: (0, pg_core_1.jsonb)('raw_email_json').$type(),
    receivedAt: (0, pg_core_1.timestamp)('received_at', { withTimezone: true }).notNull(),
    processedAt: (0, pg_core_1.timestamp)('processed_at', { withTimezone: true }),
    processedBy: (0, pg_core_1.integer)('processed_by'), // Admin who manually matched
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_payments_user').on(table.userId),
    invoiceIdx: (0, pg_core_1.index)('idx_payments_invoice').on(table.invoiceId),
    statusIdx: (0, pg_core_1.index)('idx_payments_status').on(table.status),
    senderEmailIdx: (0, pg_core_1.index)('idx_payments_sender_email').on(table.senderEmail),
    referenceIdx: (0, pg_core_1.index)('idx_payments_reference').on(table.referenceNumber),
    receivedAtIdx: (0, pg_core_1.index)('idx_payments_received_at').on(table.receivedAt),
}));
// Payment Audit Log - Audit trail for all payment operations
exports.paymentAuditLog = (0, pg_core_1.pgTable)('payment_audit_log', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    paymentId: (0, pg_core_1.integer)('payment_id').references(() => exports.payments.id),
    invoiceId: (0, pg_core_1.integer)('invoice_id').references(() => exports.invoices.id),
    userId: (0, pg_core_1.integer)('user_id').references(() => exports.mediaUsers.id),
    action: (0, pg_core_1.text)('action').notNull(), // 'created', 'matched', 'applied', 'refunded', 'manual_override', etc.
    previousState: (0, pg_core_1.jsonb)('previous_state').$type(),
    newState: (0, pg_core_1.jsonb)('new_state').$type(),
    performedBy: (0, pg_core_1.integer)('performed_by'), // Admin user ID
    notes: (0, pg_core_1.text)('notes'),
    ipAddress: (0, pg_core_1.text)('ip_address'),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    paymentIdx: (0, pg_core_1.index)('idx_payment_audit_payment').on(table.paymentId),
    invoiceIdx: (0, pg_core_1.index)('idx_payment_audit_invoice').on(table.invoiceId),
    userIdx: (0, pg_core_1.index)('idx_payment_audit_user').on(table.userId),
    actionIdx: (0, pg_core_1.index)('idx_payment_audit_action').on(table.action),
    createdAtIdx: (0, pg_core_1.index)('idx_payment_audit_created').on(table.createdAt),
}));
// ============================================
// Notification System Tables
// ============================================
// Notification types enum
exports.NOTIFICATION_TYPES = [
    'friend_request',
    'friend_request_accepted',
    'poke',
    'video_recommendation',
    'watch_party_invite',
    'achievement_unlocked',
    'comment_reply',
    'digest_completed',
    'digest_failed',
    'upload_approved',
    'upload_rejected',
    'system',
];
// Main notifications table
exports.notifications = (0, pg_core_1.pgTable)('notifications', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    type: (0, pg_core_1.text)('type').notNull().$type(),
    title: (0, pg_core_1.text)('title').notNull(),
    message: (0, pg_core_1.text)('message'),
    referenceType: (0, pg_core_1.text)('reference_type'), // 'user', 'media', 'watch_party', 'digest', 'upload', etc.
    referenceId: (0, pg_core_1.integer)('reference_id'),
    actorId: (0, pg_core_1.integer)('actor_id').references(() => exports.mediaUsers.id, { onDelete: 'set null' }),
    metadata: (0, pg_core_1.jsonb)('metadata').$type(),
    isRead: (0, pg_core_1.boolean)('is_read').default(false),
    actionUrl: (0, pg_core_1.text)('action_url'),
    groupKey: (0, pg_core_1.text)('group_key'), // For aggregation (e.g., "poke_123" to group multiple pokes from same user)
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    readAt: (0, pg_core_1.timestamp)('read_at', { withTimezone: true }),
}, (table) => ({
    userUnreadIdx: (0, pg_core_1.index)('idx_notifications_user_unread').on(table.userId, table.isRead),
    userCreatedIdx: (0, pg_core_1.index)('idx_notifications_user_created').on(table.userId, table.createdAt),
    typeIdx: (0, pg_core_1.index)('idx_notifications_type').on(table.type),
    createdAtIdx: (0, pg_core_1.index)('idx_notifications_created').on(table.createdAt),
    actorIdx: (0, pg_core_1.index)('idx_notifications_actor').on(table.actorId),
}));
// User notification preferences table
exports.notificationPreferences = (0, pg_core_1.pgTable)('notification_preferences', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    userId: (0, pg_core_1.integer)('user_id').notNull().unique().references(() => exports.mediaUsers.id, { onDelete: 'cascade' }),
    // Email toggles per notification type
    emailFriendRequest: (0, pg_core_1.boolean)('email_friend_request').default(true),
    emailFriendRequestAccepted: (0, pg_core_1.boolean)('email_friend_request_accepted').default(true),
    emailPoke: (0, pg_core_1.boolean)('email_poke').default(true),
    emailVideoRecommendation: (0, pg_core_1.boolean)('email_video_recommendation').default(true),
    emailWatchPartyInvite: (0, pg_core_1.boolean)('email_watch_party_invite').default(true),
    emailAchievement: (0, pg_core_1.boolean)('email_achievement').default(false),
    emailDigestComplete: (0, pg_core_1.boolean)('email_digest_complete').default(true),
    emailDigestFailed: (0, pg_core_1.boolean)('email_digest_failed').default(true),
    emailUploadApproved: (0, pg_core_1.boolean)('email_upload_approved').default(true),
    emailUploadRejected: (0, pg_core_1.boolean)('email_upload_rejected').default(true),
    // In-app toggles per notification type (default all on)
    inAppFriendRequest: (0, pg_core_1.boolean)('inapp_friend_request').default(true),
    inAppFriendRequestAccepted: (0, pg_core_1.boolean)('inapp_friend_request_accepted').default(true),
    inAppPoke: (0, pg_core_1.boolean)('inapp_poke').default(true),
    inAppVideoRecommendation: (0, pg_core_1.boolean)('inapp_video_recommendation').default(true),
    inAppWatchPartyInvite: (0, pg_core_1.boolean)('inapp_watch_party_invite').default(true),
    inAppAchievement: (0, pg_core_1.boolean)('inapp_achievement').default(true),
    inAppDigestComplete: (0, pg_core_1.boolean)('inapp_digest_complete').default(true),
    inAppDigestFailed: (0, pg_core_1.boolean)('inapp_digest_failed').default(true),
    inAppUploadApproved: (0, pg_core_1.boolean)('inapp_upload_approved').default(true),
    inAppUploadRejected: (0, pg_core_1.boolean)('inapp_upload_rejected').default(true),
    inAppCommentReply: (0, pg_core_1.boolean)('inapp_comment_reply').default(true),
    inAppSystem: (0, pg_core_1.boolean)('inapp_system').default(true),
    // Quiet hours settings
    quietHoursEnabled: (0, pg_core_1.boolean)('quiet_hours_enabled').default(false),
    quietHoursStart: (0, pg_core_1.text)('quiet_hours_start'), // "22:00" (24-hour format)
    quietHoursEnd: (0, pg_core_1.text)('quiet_hours_end'), // "08:00"
    updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    userIdx: (0, pg_core_1.index)('idx_notification_preferences_user').on(table.userId),
}));
// ============================================
// Geo-Blocking Tables
// ============================================
exports.GEO_BLOCKING_MODES = ['disabled', 'blocklist', 'allowlist'];
exports.geoBlockingRules = (0, pg_core_1.pgTable)('geo_blocking_rules', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    country: (0, pg_core_1.text)('country').notNull(), // ISO Alpha-2 code (required)
    countryName: (0, pg_core_1.text)('country_name'), // Display name
    region: (0, pg_core_1.text)('region'), // Optional - state/province ISO code
    city: (0, pg_core_1.text)('city'), // Optional - city name
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
    createdBy: (0, pg_core_1.integer)('created_by').references(() => exports.mediaUsers.id),
    note: (0, pg_core_1.text)('note'), // Admin note explaining why blocked
}, (table) => ({
    countryIdx: (0, pg_core_1.index)('idx_geo_blocking_country').on(table.country),
    uniqueRule: (0, pg_core_1.uniqueIndex)('idx_geo_blocking_unique').on(table.country, table.region, table.city),
}));
// ============================================
// Inbox Publishing Tracking
// ============================================
exports.INBOX_FILE_TYPES = ['clip', 'scene', 'video'];
exports.publishedInboxFiles = (0, pg_core_1.pgTable)('published_inbox_files', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    sourceInboxPath: (0, pg_core_1.text)('source_inbox_path').notNull(), // Original path in inbox
    filename: (0, pg_core_1.text)('filename').notNull(),
    publishedAt: (0, pg_core_1.timestamp)('published_at', { withTimezone: true }).defaultNow(),
    publishedToPath: (0, pg_core_1.text)('published_to_path'), // Destination path in public directory
    publicMediaId: (0, pg_core_1.integer)('public_media_id').references(() => exports.publicMedia.id, { onDelete: 'set null' }),
    fileType: (0, pg_core_1.text)('file_type').$type().notNull(),
}, (table) => ({
    sourcePathIdx: (0, pg_core_1.index)('idx_published_inbox_source').on(table.sourceInboxPath),
    fileTypeIdx: (0, pg_core_1.index)('idx_published_inbox_file_type').on(table.fileType),
}));
// ============================================
// Video OCR Results Table
// ============================================
exports.OCR_TEXT_TYPES = ['credits', 'title_card', 'overlay', 'unknown'];
exports.videoOcrResults = (0, pg_core_1.pgTable)('video_ocr_results', {
    id: (0, pg_core_1.serial)('id').primaryKey(),
    digestId: (0, pg_core_1.integer)('digest_id').notNull(),
    videoId: (0, pg_core_1.integer)('video_id').notNull(),
    frameIndex: (0, pg_core_1.integer)('frame_index').notNull(),
    timestamp: (0, pg_core_1.real)('timestamp').notNull(),
    extractedText: (0, pg_core_1.text)('extracted_text').notNull(),
    confidence: (0, pg_core_1.real)('confidence'),
    textType: (0, pg_core_1.text)('text_type').$type(),
    sourceFrame: (0, pg_core_1.text)('source_frame').notNull(),
    createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true }).defaultNow(),
}, (table) => ({
    digestIdx: (0, pg_core_1.index)('idx_video_ocr_results_digest').on(table.digestId),
    videoIdx: (0, pg_core_1.index)('idx_video_ocr_results_video').on(table.videoId),
}));
//# sourceMappingURL=schema.js.map