import { z } from 'zod'; import { RedditAccountOwnerSchema } from './session.js'; export const OutreachCandidateStatusSchema = z.enum([ 'discovered', 'screening', 'ready', 'sending', 'retryable', ]); export const OutreachStageCountsSchema = z.strictObject({ discovered: z.number().int().nonnegative(), screening: z.number().int().nonnegative(), ready: z.number().int().nonnegative(), sending: z.number().int().nonnegative(), retryable: z.number().int().nonnegative(), }); export const OutreachPreparationSchema = z.strictObject({ message: z.string(), imageAnalysis: z.string(), detectedGender: z.enum(['male', 'female', 'other', 'unknown']), attractivenessScore: z.number().int().min(1).max(100).nullable(), physiqueScore: z.number().int().min(1).max(10).nullable(), physiqueTargeting: z.strictObject({ enabled: z.boolean(), minScore: z.number().int().min(1).max(10), maxScore: z.number().int().min(1).max(10), }).nullable(), sourceImageUrl: z.string().nullable(), strategyId: z.string().nullable(), experimentId: z.string().nullable(), promptVersion: z.string().nullable(), selectionReason: z.enum(['explore', 'exploit']).nullable(), modelId: z.string(), toneId: z.string(), scripted: z.boolean(), operatorEdited: z.boolean().default(false), }); export const OutreachCandidateSchema = z.strictObject({ postId: z.string(), subreddit: z.string(), author: z.string(), title: z.string(), postUrl: z.string(), targetComment: z.strictObject({ body: z.string(), permalink: z.string(), }).nullable().default(null), sourceType: z.enum(['image', 'chat']), status: OutreachCandidateStatusSchema, priority: z.number(), postCreatedAt: z.number(), discoveredAt: z.number(), updatedAt: z.number(), availableAt: z.number(), attemptCount: z.number().int().nonnegative(), hasPreparedMessage: z.boolean(), physiqueScore: z.number().int().min(1).max(10).nullable().default(null), preparation: OutreachPreparationSchema.nullable().default(null), note: z.string().nullable(), owner: RedditAccountOwnerSchema.nullable(), }); export const OutreachFunnelResponseSchema = z.strictObject({ generatedAt: z.number(), activeCount: z.number().int().nonnegative(), stages: OutreachStageCountsSchema, outcomes: z.strictObject({ sent: z.number().int().nonnegative(), rejected: z.number().int().nonnegative(), }), rejectionReasons: z.array(z.strictObject({ reason: z.string(), count: z.number().int().positive(), })).default([]), oldestActiveAt: z.number().nullable(), candidates: z.array(OutreachCandidateSchema), }); export const OutreachClearResponseSchema = z.strictObject({ success: z.literal(true), cleared: z.strictObject({ discovered: z.number().int().nonnegative(), screening: z.number().int().nonnegative(), ready: z.number().int().nonnegative(), retryable: z.number().int().nonnegative(), total: z.number().int().nonnegative(), }), retainedSending: z.number().int().nonnegative(), }); export const OutreachMessageUpdateRequestSchema = z.strictObject({ message: z.string().trim().min(1).max(2000), }); export const OutreachMessageUpdateResponseSchema = z.strictObject({ success: z.literal(true), postId: z.string(), message: z.string(), }); export const OutreachCandidateDeleteResponseSchema = z.strictObject({ success: z.literal(true), postId: z.string(), }); export type OutreachCandidateStatus = z.infer; export type OutreachCandidate = z.infer; export type OutreachFunnelResponse = z.infer; export type OutreachClearResponse = z.infer; export type OutreachMessageUpdateRequest = z.infer; export type OutreachMessageUpdateResponse = z.infer; export type OutreachCandidateDeleteResponse = z.infer;