/**
 * Core Type Definitions for TranslatePressZone Translation API
 *
 * This file contains all core types, interfaces, and enums used throughout the API.
 * Types are designed to be compatible with Zod for runtime validation.
 */

import type { TranslationExecutionMode } from '@prisma/client';
import { z } from 'zod';
import type { ExceptionRule } from '../services/exceptionService';

// ============================================================================
// ENUMS
// ============================================================================

/**
 * User account status
 */
export enum UserStatus {
  ACTIVE = 'active',
  SUSPENDED = 'suspended',
  DELETED = 'deleted',
}

/**
 * Subscription plan tiers
 */
export enum SubscriptionPlan {
  STARTER = 'starter',
  PROFESSIONAL = 'professional',
  ENTERPRISE = 'enterprise',
}

/**
 * Billing cycle options
 */
export enum BillingCycle {
  MONTHLY = 'monthly',
  ANNUAL = 'annual',
}

/**
 * Subscription status
 */
export enum SubscriptionStatus {
  ACTIVE = 'active',
  CANCELLED = 'cancelled',
  SUSPENDED = 'suspended',
  PAST_DUE = 'past_due',
}

/**
 * Translation job status lifecycle
 */
export enum TranslationStatus {
  PENDING = 'pending',
  PROCESSING = 'processing',
  COMPLETED = 'completed',
  FAILED = 'failed',
  CANCELLED = 'cancelled',
}

/**
 * Translation tone/style options
 */
export enum Tone {
  NEUTRAL = 'neutral',
  FORMAL = 'formal',
  CASUAL = 'casual',
}

/**
 * Credit transaction types
 */
export enum CreditTransactionType {
  ALLOCATION = 'allocation',
  DEDUCTION = 'deduction',
  REFUND = 'refund',
}

/**
 * Payment status
 */
export enum PaymentStatus {
  PENDING = 'pending',
  COMPLETED = 'completed',
  FAILED = 'failed',
  REFUNDED = 'refunded',
}

/**
 * Payment type
 */
export enum PaymentType {
  SUBSCRIPTION_PAYMENT = 'subscription_payment',
  ONE_TIME = 'one_time',
  REFUND = 'refund',
}

/**
 * Admin user roles
 */
export enum AdminRole {
  ADMIN = 'admin',
  SUPPORT = 'support',
}

// ============================================================================
// ZOD SCHEMAS (for validation)
// ============================================================================

/**
 * ISO 639-1 language code (2-letter or with optional region: en, zh, en-us, zh-cn)
 */
export const LanguageCodeSchema = z.string().min(2).max(7).regex(/^[a-z]{2}(-[a-z]{2})?$/);

/**
 * Translation tone schema
 */
export const ToneSchema = z.enum(['neutral', 'formal', 'casual']);

/**
 * Subscription plan schema
 */
export const SubscriptionPlanSchema = z.enum(['starter', 'professional', 'enterprise']);

/**
 * Translation status schema
 */
export const TranslationStatusSchema = z.enum(['pending', 'processing', 'completed', 'failed', 'cancelled']);

// ============================================================================
// AUTHENTICATION & AUTHORIZATION
// ============================================================================

/**
 * JWT payload structure for access tokens
 */
export interface JWTPayload {
  /** User UUID */
  userId: string;
  /** User email */
  email: string;
  /** Subscription plan tier */
  plan: string;
  /** Subscription status */
  subscriptionStatus: SubscriptionStatus;
  /** Plugin identifier from active subscription (e.g. 'translate', 'international') */
  plugin: string;
  /** Token issue time (Unix timestamp) */
  iat?: number;
  /** Token expiration time (Unix timestamp) */
  exp?: number;
}

/**
 * JWT refresh token payload
 */
export interface JWTRefreshPayload {
  /** User UUID */
  userId: string;
  /** Token version for invalidation */
  version?: string;
  /** Token issue time (Unix timestamp) */
  iat?: number;
  /** Token expiration time (Unix timestamp) */
  exp?: number;
}

/**
 * API Key data structure (stored in database)
 */
export interface ApiKeyData {
  /** API Key UUID */
  id: string;
  /** User UUID */
  userId: string;
  /** SHA-256 hash of the key */
  keyHash: string;
  /** First 8 characters visible (e.g., "sk_live_") */
  prefix: string;
  /** User-defined name for the key */
  name: string;
  /** Whether the key is active */
  isActive: boolean;
  /** Last time the key was used */
  lastUsedAt: Date | null;
  /** Key creation timestamp */
  createdAt: Date;
}

export interface LicenseData {
  id: string;
  userId: string;
  plugin: string;
  planTier: string;
  executionMode: TranslationExecutionMode;
  expiresAt: Date;
}

/**
 * API Key response (returned to user on creation)
 */
export interface ApiKeyResponse {
  /** API Key UUID */
  id: string;
  /** The actual key (only shown once on creation) */
  key?: string;
  /** Key prefix for identification */
  prefix: string;
  /** User-defined name */
  name: string;
  /** Whether the key is active */
  isActive: boolean;
  /** Last usage timestamp */
  lastUsedAt: string | null;
  /** Creation timestamp */
  createdAt: string;
}

// ============================================================================
// TRANSLATION API TYPES
// ============================================================================

/**
 * Synchronous translation request
 * Accepts either structured fields (title/excerpt/content) or a single content blob.
 * At least one of title, excerpt, or content must be provided.
 */
export interface TranslationRequest {
  /** Source language (ISO 639-1 code) */
  sourceLang: string;
  /** Target language (ISO 639-1 code) */
  targetLang: string;
  /** Post title (structured field) */
  title?: string;
  /** Post excerpt (structured field, may contain HTML) */
  excerpt?: string;
  /** Content to translate (may contain HTML; also used as legacy single-blob field) */
  content?: string;
  /** Translation tone/style */
  tone?: Tone;
  /** Strings the client never wants translated (supplied per request; never stored) */
  exceptions?: ExceptionRule[];
  /** Optional client job ID for tracking */
  clientJobId?: string;
}

/**
 * Synchronous translation response
 */
export interface TranslationResponse {
  /** Translation job UUID */
  jobId: string;
  /** Translation status (should be 'completed' for sync) */
  status: TranslationStatus;
  /** Translated content (legacy single-blob or combined text for backward compat) */
  translation: string;
  /** Translated post title (structured response) */
  translatedTitle?: string;
  /** Translated post excerpt (structured response) */
  translatedExcerpt?: string;
  /** Translated post content (structured response) */
  translatedContent?: string;
  /** Number of source characters billed (HTML stripped) */
  charactersUsed: number;
  /** Internal cost in USD (Gemini API cost) */
  cost: number;
  /** Customer-facing cost in USD (based on subscription rate) */
  customerCost: number;
  /** Processing time in milliseconds */
  processingTimeMs: number;
  /** Remaining credit balance */
  creditBalance: number;
}

/**
 * Asynchronous job submission request
 */
export interface JobSubmitRequest {
  /** Source language (ISO 639-1 code) */
  sourceLang: string;
  /** Target language (ISO 639-1 code) */
  targetLang: string;
  /** Legacy structured title */
  title?: string;
  /** Legacy structured excerpt */
  excerpt?: string;
  /** Legacy single-blob or structured content */
  content?: string;
  /** Generic structured text fields */
  fields?: Record<string, string>;
  /** Translation tone/style */
  tone?: Tone;
  /** Strings the client never wants translated (supplied per request; never stored) */
  exceptions?: ExceptionRule[];
  /** Webhook URL for completion notification */
  callbackUrl?: string;
  /** HMAC secret for webhook verification */
  callbackSecret?: string;
  /** Optional client job ID for tracking */
  clientJobId?: string;
}

/**
 * Job submission response
 */
export interface JobSubmitResponse {
  /** Translation job UUID */
  jobId: string;
  /** Immutable backend submission UUID for idempotent bulk requests */
  submissionId?: string;
  /** Initial job status (usually 'pending') */
  status: TranslationStatus;
  /** Estimated completion time (if available) */
  estimatedCompletionTime?: string;
  /** Client job ID (if provided) */
  clientJobId?: string;
}

/**
 * Job status check response
 */
export interface JobStatusResponse {
  /** Translation job UUID */
  jobId: string;
  /** Immutable backend submission UUID, when the job came from a bulk submission */
  submissionId?: string;
  /** Client job ID (if provided) */
  clientJobId?: string;
  /** Current job status */
  status: TranslationStatus;
  /** Source language */
  sourceLang: string;
  /** Target language */
  targetLang: string;
  /** Tone used */
  tone: Tone;
  /** Segmented resource discriminator */
  resourceType?: 'site_content';
  /** Segmented resource contract version */
  contractVersion?: number;
  /** Source snapshot revision used by this job */
  sourceRevision?: string;
  /** Translated content (if completed) */
  translation?: string;
  /** Translated post title (if completed) */
  translatedTitle?: string;
  /** Translated post excerpt (if completed) */
  translatedExcerpt?: string;
  /** Translated post content (if completed) */
  translatedContent?: string;
  /** Translated generic fields (if completed) */
  translatedFields?: Record<string, string>;
  /** Source characters billed (if completed) */
  charactersUsed?: number;
  /** Internal cost in USD (if completed) */
  cost?: number;
  /** Customer-facing cost in USD (if completed) */
  customerCost?: number;
  /** Error message (if failed) */
  errorMessage?: string;
  /** Processing time in milliseconds (if completed) */
  processingTimeMs?: number;
  /** Job creation timestamp */
  createdAt: string;
  /** Job update timestamp */
  updatedAt: string;
  /** Completion timestamp (if completed/failed) */
  completedAt?: string;
}

// ============================================================================
// WEBHOOK TYPES
// ============================================================================

/**
 * Webhook payload sent on job completion
 */
export interface WebhookPayload {
  /** Event type */
  event: 'translation.completed' | 'translation.failed' | 'bulk_translation.completed' | 'bulk_content_translation.completed';
  /** Translation job UUID */
  jobId: string;
  /** Client job ID (if provided) */
  clientJobId?: string;
  /** Immutable backend submission UUID for callback reconciliation */
  submission_id?: string;
  /** Monotonic terminal callback sequence for this backend job */
  event_sequence?: number;
  /** Delivery identifier, unique per webhook attempt */
  deliveryId?: string;
  /** Job status */
  status: TranslationStatus;
  /** Segmented resource discriminator */
  resourceType?: 'site_content';
  /** Segmented resource contract version */
  contractVersion?: number;
  /** Source snapshot revision used by this job */
  sourceRevision?: string;
  /** Attempt authority echoed only to the authenticated callback */
  attemptToken?: string;
  /** Requested target language echoed to the authenticated callback */
  targetLang?: string;
  /** Translated content (if completed) */
  translation?: string;
  /** Legacy structured aliases */
  translatedTitle?: string;
  translatedExcerpt?: string;
  translatedContent?: string;
  /** Generic translated fields */
  translatedFields?: Record<string, string>;
  /** Source characters billed (if completed) */
  charactersUsed?: number;
  /** Customer-facing cost in USD (if completed) */
  cost?: number;
  /** Error message (if failed) */
  errorMessage?: string;
  /** Processing time in milliseconds */
  processingTimeMs?: number;
  /** Timestamp of completion/failure */
  timestamp: string;
  /** HMAC signature (in X-TPZ-Signature header) */
  signature?: string;
}

/**
 * Webhook delivery record
 */
export interface WebhookDelivery {
  /** Delivery UUID */
  id: string;
  /** Job UUID */
  jobId: string;
  /** Attempt number */
  attemptNumber: number;
  /** Whether delivery succeeded */
  success: boolean;
  /** HTTP status code */
  httpStatus?: number;
  /** Response body from webhook endpoint */
  responseBody?: string;
  /** Error message (if failed) */
  errorMessage?: string;
  /** Attempt timestamp */
  attemptedAt: Date;
}

// ============================================================================
// PAYPAL WEBHOOK TYPES
// ============================================================================

/**
 * PayPal webhook event
 */
export interface PayPalWebhookEvent {
  /** Event ID */
  id: string;
  /** Event type (e.g., 'BILLING.SUBSCRIPTION.ACTIVATED') */
  event_type: string;
  /** Event version */
  event_version: string;
  /** Event creation time */
  create_time: string;
  /** Resource type */
  resource_type: string;
  /** Resource data */
  resource: {
    /** Subscription ID */
    id?: string;
    /** Plan ID */
    plan_id?: string;
    /** Subscriber info */
    subscriber?: {
      email_address?: string;
      payer_id?: string;
    };
    /** Subscription status */
    status?: string;
    /** Status update time */
    status_update_time?: string;
    /** Billing info */
    billing_info?: {
      outstanding_balance?: {
        value?: string;
        currency_code?: string;
      };
      cycle_executions?: Array<{
        tenure_type?: string;
        sequence?: number;
        cycles_completed?: number;
        cycles_remaining?: number;
      }>;
    };
    [key: string]: unknown;
  };
  /** Summary */
  summary?: string;
  /** Links */
  links?: Array<{
    href: string;
    rel: string;
    method: string;
  }>;
}

// ============================================================================
// USER & SUBSCRIPTION TYPES
// ============================================================================

/**
 * User data
 */
export interface UserData {
  /** User UUID */
  id: string;
  /** Email address */
  email: string;
  /** Whether email is verified */
  emailVerified: boolean;
  /** Account status */
  status: UserStatus;
  /** Account creation timestamp */
  createdAt: Date;
  /** Last update timestamp */
  updatedAt: Date;
}

/**
 * User registration request
 */
export interface UserRegistrationRequest {
  /** Email address */
  email: string;
  /** Password (min 8 characters) */
  password: string;
}

/**
 * User login request
 */
export interface UserLoginRequest {
  /** Email address */
  email: string;
  /** Password */
  password: string;
}

/**
 * Authentication response
 */
export interface AuthResponse {
  /** Access token (JWT) */
  accessToken: string;
  /** Refresh token (JWT) */
  refreshToken: string;
  /** User data */
  user: {
    id: string;
    email: string;
    emailVerified: boolean;
    plan: string;
    subscriptionStatus: SubscriptionStatus;
  };
}

/**
 * Subscription tier details
 */
export interface SubscriptionTierDetails {
  /** Plan tier */
  plan: string;
  /** Billing cycle */
  billingCycle: BillingCycle;
  /** Subscription status */
  status: SubscriptionStatus;
  /** PayPal subscription ID */
  paypalSubscriptionId?: string;
  /** Current period start */
  currentPeriodStart: Date;
  /** Current period end */
  currentPeriodEnd: Date;
  /** Whether subscription cancels at period end */
  cancelAtPeriodEnd: boolean;
  /** Current credit balance */
  creditBalance: number;
  /** Monthly credit allocation */
  creditAllocation: number;
  /** Rate limit (requests per minute, 0 = unlimited) */
  rateLimit: number;
}

/**
 * Credit transaction
 */
export interface CreditTransaction {
  /** Transaction UUID */
  id: string;
  /** User UUID */
  userId: string;
  /** Transaction type */
  type: CreditTransactionType;
  /** Amount (negative for deductions) */
  amount: number;
  /** Balance after transaction */
  balanceAfter: number;
  /** Transaction description */
  description: string;
  /** Related job ID (if applicable) */
  relatedJobId?: string;
  /** Related payment ID (if applicable) */
  relatedPaymentId?: string;
  /** Transaction timestamp */
  createdAt: Date;
}

/**
 * Payment record
 */
export interface PaymentRecord {
  /** Payment UUID */
  id: string;
  /** User UUID */
  userId: string;
  /** PayPal payment ID */
  paypalPaymentId?: string;
  /** Amount in USD */
  amount: number;
  /** Currency code (usually USD) */
  currency: string;
  /** Payment status */
  status: PaymentStatus;
  /** Payment type */
  type: PaymentType;
  /** Related subscription ID */
  subscriptionId?: string;
  /** Payment timestamp */
  createdAt: Date;
}

// ============================================================================
// PAGINATION & FILTERING
// ============================================================================

/**
 * Pagination parameters
 */
export interface PaginationParams {
  /** Page number (1-indexed) */
  page?: number;
  /** Items per page */
  limit?: number;
  /** Sort field */
  sortBy?: string;
  /** Sort order */
  sortOrder?: 'asc' | 'desc';
}

/**
 * Paginated response wrapper
 */
export interface PaginatedResponse<T> {
  /** Array of items */
  data: T[];
  /** Pagination metadata */
  pagination: {
    /** Current page */
    page: number;
    /** Items per page */
    limit: number;
    /** Total number of items */
    total: number;
    /** Total number of pages */
    totalPages: number;
    /** Whether there is a next page */
    hasNext: boolean;
    /** Whether there is a previous page */
    hasPrev: boolean;
  };
}

/**
 * Date range filter
 */
export interface DateRangeFilter {
  /** Start date (ISO 8601) */
  startDate?: string;
  /** End date (ISO 8601) */
  endDate?: string;
}

/**
 * Job filter parameters
 */
export interface JobFilterParams extends PaginationParams, DateRangeFilter {
  /** Filter by status */
  status?: TranslationStatus | TranslationStatus[];
  /** Filter by source language */
  sourceLang?: string;
  /** Filter by target language */
  targetLang?: string;
  /** Filter by client job ID */
  clientJobId?: string;
}

// ============================================================================
// ERROR TYPES
// ============================================================================

/**
 * API error response
 */
export interface ErrorResponse {
  /** Error flag */
  error: true;
  /** Error code (e.g., 'INVALID_API_KEY', 'INSUFFICIENT_CREDITS') */
  code: string;
  /** Human-readable error message */
  message: string;
  /** Additional error details (optional) */
  details?: Record<string, unknown>;
  /** Request ID for debugging */
  requestId?: string;
  /** Timestamp */
  timestamp: string;
}

/**
 * Validation error details
 */
export interface ValidationError {
  /** Field that failed validation */
  field: string;
  /** Error message */
  message: string;
  /** Validation rule that failed */
  rule?: string;
  /** Expected value/format */
  expected?: string;
  /** Actual value received */
  received?: string;
}

/**
 * Validation error response
 */
export interface ValidationErrorResponse extends ErrorResponse {
  code: 'VALIDATION_ERROR';
  /** Array of validation errors */
  errors: ValidationError[];
}

// ============================================================================
// ADMIN PANEL TYPES
// ============================================================================

/**
 * Admin user data
 */
export interface AdminUserData {
  /** Admin UUID */
  id: string;
  /** Email address */
  email: string;
  /** Admin role */
  role: AdminRole;
  /** Whether admin is active */
  isActive: boolean;
  /** Last login timestamp */
  lastLoginAt: Date | null;
  /** Account creation timestamp */
  createdAt: Date;
  /** Last update timestamp */
  updatedAt: Date;
}

/**
 * System metrics
 */
export interface SystemMetrics {
  /** Total users */
  totalUsers: number;
  /** Active subscriptions */
  activeSubscriptions: number;
  /** Total translations (all time) */
  totalTranslations: number;
  /** Translations today */
  translationsToday: number;
  /** Total revenue */
  totalRevenue: number;
  /** Revenue this month */
  revenueThisMonth: number;
  /** Average processing time (ms) */
  avgProcessingTime: number;
  /** Error rate (percentage) */
  errorRate: number;
}

/**
 * System setting
 */
export interface SystemSetting {
  /** Setting UUID */
  id: string;
  /** Setting key */
  key: string;
  /** Setting value (JSON) */
  value: unknown;
  /** Setting description */
  description: string;
  /** Last update timestamp */
  updatedAt: Date;
  /** Admin who last updated */
  updatedBy?: string;
}

// ============================================================================
// AUDIT LOG TYPES
// ============================================================================

/**
 * Audit log entry
 */
export interface AuditLogEntry {
  /** Log UUID */
  id: string;
  /** User UUID (if applicable) */
  userId?: string;
  /** Action performed (e.g., 'user.login', 'api_key.created') */
  action: string;
  /** Resource type (e.g., 'user', 'api_key', 'translation_job') */
  resourceType?: string;
  /** Resource UUID */
  resourceId?: string;
  /** IP address */
  ipAddress?: string;
  /** User agent string */
  userAgent?: string;
  /** Additional details (JSON) */
  details?: Record<string, unknown>;
  /** Timestamp */
  createdAt: Date;
}

// ============================================================================
// GOOGLE GEMINI API SERVICE TYPES
// ============================================================================

/**
 * Request to Google Gemini API service
 */
export interface GeminiTranslationRequest {
  /** Source language */
  source_lang: string;
  /** Target language */
  target_lang: string;
  /** Content to translate */
  content: string;
  /** Tone/style */
  tone: Tone;
}

/**
 * Response from Google Gemini API service
 */
export interface GeminiTranslationResponse {
  /** Translated content */
  translation: string;
  /** Generic translated fields */
  translatedFields?: Record<string, string>;
  /** Total tokens used (input + output) */
  tokens_used: number;
  /** Gemini API prompt/input tokens */
  input_tokens: number;
  /** Gemini API completion/output tokens */
  output_tokens: number;
  /** Processing time in milliseconds */
  processing_time_ms: number;
  /** Which model was actually used (primary or fallback) */
  model_used: string;
}


// ============================================================================
// RATE LIMITING TYPES
// ============================================================================

/**
 * Rate limit info
 */
export interface RateLimitInfo {
  /** Requests allowed per window */
  limit: number;
  /** Requests remaining in current window */
  remaining: number;
  /** Timestamp when window resets (Unix timestamp) */
  reset: number;
  /** Window duration in seconds */
  windowMs: number;
}

// ============================================================================
// TYPE GUARDS
// ============================================================================

/**
 * Check if a value is a valid Tone
 */
export function isTone(value: unknown): value is Tone {
  return value === Tone.NEUTRAL || value === Tone.FORMAL || value === Tone.CASUAL;
}

/**
 * Check if a value is a valid SubscriptionPlan
 */
export function isSubscriptionPlan(value: unknown): value is SubscriptionPlan {
  return (
    value === SubscriptionPlan.STARTER ||
    value === SubscriptionPlan.PROFESSIONAL ||
    value === SubscriptionPlan.ENTERPRISE
  );
}

/**
 * Check if a value is a valid TranslationStatus
 */
export function isTranslationStatus(value: unknown): value is TranslationStatus {
  return (
    value === TranslationStatus.PENDING ||
    value === TranslationStatus.PROCESSING ||
    value === TranslationStatus.COMPLETED ||
    value === TranslationStatus.FAILED ||
    value === TranslationStatus.CANCELLED
  );
}

// ============================================================================
// BULK TRANSLATION TYPES
// ============================================================================

/**
 * Single string item for bulk translation input
 */
export interface BulkStringItem {
  /** Caller-assigned string identifier (returned unchanged in results) */
  id: string;
  /** Text/HTML content to translate */
  content: string;
}

/**
 * Single string result from a bulk translation
 */
export interface BulkTranslateResponse {
  /** Per-string results */
  results: BulkStringResult[];
  /** Which model was actually used (primary or fallback) */
  model_used: string;
  /** Total tokens consumed by the Gemini API call (input + output) */
  tokens_used: number;
  /** Gemini API prompt/input tokens */
  input_tokens: number;
  /** Gemini API completion/output tokens */
  output_tokens: number;
}

export interface BulkStringResult {
  /** Matches the input id */
  id: string;
  /** Translated content (empty string on failure) */
  translation: string;
  /** Whether this particular string succeeded */
  success: boolean;
  /** Error message if success is false */
  error?: string;
}

/**
 * Request body for POST /v1/translate/bulk
 */
export interface BulkTranslationRequest {
  strings: BulkStringItem[];
  sourceLang: string;
  targetLang: string;
  tone?: Tone;
  exceptions?: ExceptionRule[];
}

/**
 * Response body for POST /v1/translate/bulk
 */
export interface BulkTranslationResponse {
  results: BulkStringResult[];
  totalCharactersUsed: number;
  failedCount: number;
}

/**
 * Bull job data for async bulk-strings jobs (POST /v1/jobs/bulk-strings)
 */
export interface BulkTranslationJobData {
  /** Bull job UUID (generated by the route handler) */
  jobId: string;
  /** Client reference used by WordPress callback reconciliation */
  clientJobId?: string;
  /** User UUID */
  userId: string;
  /** Strings to translate */
  strings: BulkStringItem[];
  /** Source language code */
  sourceLang: string;
  /** One or more target language codes */
  targetLangs: string[];
  /** Translation tone */
  tone?: string;
  /** Strings the client never wants translated (supplied per request; never stored) */
  exceptions?: ExceptionRule[];
  /** Webhook URL to call when all batches complete */
  callbackUrl: string;
  /** HMAC secret for webhook verification */
  callbackSecret: string;
}

/**
 * Webhook payload sent when a bulk-strings async job completes
 */
export interface BulkWebhookPayload {
  event: 'bulk_translation.completed';
  job_id: string;
  submission_id?: string;
  event_sequence?: number;
  /** Per-language results: { "es": [{id, translation, success}], "fr": [...] } */
  results_by_lang: Record<string, BulkStringResult[]>;
  total_characters_used: number;
  failed_count: number;
  timestamp: string;
}

/**
 * Maximum number of (post, language) items in one bulk-content job (POST /v1/jobs/bulk-content)
 */
export const BULK_CONTENT_MAX_ITEMS = 20;

/**
 * Canonical item persisted in queue_payload and reconstructed into Bull data.
 *
 * The route normalizes legacy aliases into fields before persistence. Aliases
 * remain optional here for the compatibility boundary, but fields is required
 * for the durable payload so arbitrary ACF/SEO keys cannot be dropped by a
 * queue reconstruction.
 */
export interface BulkContentQueueItem {
  /** Client-chosen identity, e.g. "content:{postId}:{lang}" — echoed back in results */
  ref: string;
  targetLang: string;
  fields: Record<string, string>;
  /** Legacy aliases retained only for compatibility with old queue fixtures. */
  title?: string;
  excerpt?: string;
  content?: string;
}

/**
 * Secret-free canonical payload persisted before the durable queue sweep.
 */
export interface BulkContentQueuePayload {
  type: 'bulk-content';
  jobId: string;
  submissionId: string;
  clientJobId: string;
  userId: string;
  plugin: string;
  items: BulkContentQueueItem[];
  sourceLang: string;
  tone: string;
  callbackUrl: string;
}

/**
 * A single (post, language) item within a bulk-content job.
 */
export interface BulkContentItemInput {
  /** Client-chosen identity, e.g. "content:{postId}:{lang}" — echoed back in results */
  ref: string;
  targetLang: string;
  /**
   * Canonical arbitrary structured source fields sent to the worker. New route
   * admissions always persist this property; it remains optional here so old
   * Bull fixtures and compatibility callers using only the legacy aliases keep
   * type-checking while the queue migration is rolled out.
   */
  fields?: Record<string, string>;
  /** Legacy aliases accepted by the route and normalized into fields */
  title?: string;
  excerpt?: string;
  content?: string;
}

/**
 * Result of translating a single bulk-content item.
 */
export interface BulkContentItemResult {
  ref: string;
  status: 'completed' | 'failed';
  /** Translated fields with exactly the same keys as the validated input */
  fields?: Record<string, string>;
  translatedTitle?: string;
  translatedExcerpt?: string;
  translatedContent?: string;
  error?: string;
}

/**
 * Bull job data for async bulk-content jobs (POST /v1/jobs/bulk-content)
 */
export interface BulkContentTranslationJobData {
  /** Bull job UUID (generated by the route handler) */
  jobId: string;
  /**
   * Immutable backend submission UUID used for create-or-return-existing. New
   * queue payloads always carry it; optional keeps pre-idempotency Bull data
   * and legacy test fixtures source-compatible during the migration window.
   */
  submissionId?: string;
  /** Client reference used by WordPress callback reconciliation */
  clientJobId?: string;
  /** User UUID */
  userId: string;
  /** (post, language) items to translate */
  items: BulkContentItemInput[];
  /** Source language code */
  sourceLang: string;
  /** Translation tone */
  tone?: string;
  /** Webhook URL to call when all items complete */
  callbackUrl: string;
  /** HMAC secret for webhook verification */
  callbackSecret: string;
}

/**
 * Webhook payload sent when a bulk-content async job completes
 */
export interface BulkContentWebhookPayload {
  event: 'bulk_content_translation.completed';
  job_id: string;
  /** Immutable backend submission UUID for callback reconciliation */
  submission_id: string;
  /** Monotonic terminal callback sequence for this backend job */
  event_sequence: number;
  clientJobId?: string;
  results: BulkContentItemResult[];
  total_characters_used: number;
  failed_count: number;
  timestamp: string;
}

// ============================================================================
// UTILITY TYPES
// ============================================================================

/**
 * Make all properties optional recursively
 */
export type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

/**
 * Make specific properties required
 */
export type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };

/**
 * Omit properties from type
 */
export type OmitStrict<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

/**
 * Extract non-nullable properties
 */
export type NonNullableFields<T> = {
  [P in keyof T]: NonNullable<T[P]>;
};
