/**
 * Unified LLM job library - single entry point for all async AI tasks.
 *
 * Responsibilities:
 *   enqueueLlmJob                  - insert a PENDING row in llm_jobs, return jobId
 *   enqueueVendorAdmissionReviewOnce - idempotent VENDOR_VIOLATION enqueue
 *
 * All LLM job enqueues must go through this module so every invocation is logged,
 * auditable, and retryable. Job execution is handled by the JobKind plugin system
 * in kinds/registry.ts + runner.ts.
 *
 * REVIEW_PRESCORING is NOT a queued job — it runs synchronously from
 * admin/resources/review-moderation/actions.ts::prescoreViaAi. It is not enqueued here.
 */

import type { DrizzleClient } from '@/server/db/client.js';
import * as llmJobsQ from '@/server/db/queries/llm-jobs.js';

// ─── Types ────────────────────────────────────────────────────────────────────

export type LlmJobType =
  | 'DEAL_MODERATION'
  | 'IMAGE_APPROVAL'
  | 'REVIEW_PRESCORING'
  | 'TRANSLATION'
  | 'VENDOR_VIOLATION';
export type LlmDecision = 'APPROVE' | 'FLAG' | 'REJECT';

export interface EnqueueLlmJobInput {
  id?: string;
  jobType: LlmJobType;
  targetId: string;
  targetType: 'DEAL' | 'IMAGE' | 'REVIEW_REMOVAL' | 'VENDOR';
  inputPayload: Record<string, unknown>;
  e2eRunId?: string;
  queueChainOverride?: Array<{ llmProviderId: string; model: string }>;
}

// ─── Defaults ─────────────────────────────────────────────────────────────────

/**
 * Default deal moderation prompt used when no override is stored in system_config.
 * Evaluate the deal for: spam, profanity, one-sided political/religious content,
 * misleading pricing, prohibited items.
 * Respond with exactly: DECISION: APPROVE  or  DECISION: FLAG\nREASON: <text>
 */
export const DEFAULT_MODERATION_PROMPT = `You are a content moderator for Multideal, a Hebrew-language marketplace for transparent discounted deals.

You will receive deal text fields and optionally an image. Evaluate EVERYTHING together.

FLAG the deal if ANY of the following apply:

TEXT checks:
- Spam, duplicate filler text, or no real deal content
- Profanity or offensive language
- Misleading or implausible pricing (claimed original price is inflated)
- Prohibited items (weapons, drugs, counterfeit goods)

IMAGE checks (apply only if an image is provided):
1. NSFW / Adult: nudity, sexually suggestive imagery, or explicit content
2. Violence / Harm: weapons, blood, or graphic content
3. Hate / Politics / Religion: political campaign logos, hate symbols, or aggressive religious imagery
4. Platform Bypass (Spam): QR codes, visible phone numbers, or external URLs in the image attempting to bypass the platform
5. Low Quality / Scam: "you won" badges, heavy stock-photo watermarks, or completely irrelevant abstract images
6. Image-Text Mismatch: the image does not logically match the deal description (e.g., a pizza deal showing a car)

Respond with EXACTLY one of the following formats (no extra text):
DECISION: APPROVE
or
DECISION: FLAG
REASON: <brief explanation in English, max 200 characters>`;

// ─── Public API ───────────────────────────────────────────────────────────────

/**
 * Insert a new PENDING llm_jobs row and return the job ID.
 * The job will be processed by the next cron run via the JobKind runner pipeline.
 */
export async function enqueueLlmJob(db: DrizzleClient, input: EnqueueLlmJobInput): Promise<string> {
  return llmJobsQ.enqueue(db, input);
}

/**
 * Idempotently enqueue a VENDOR_VIOLATION (admission review) job for a vendor.
 *
 * Skips insertion if a PENDING job already exists for the same vendor so that
 * duplicate calls from register.ts (session branch) and otp-verify.ts (guest
 * branch) never create duplicate queue entries.
 *
 * Returns the job ID if a new job was created, or null if skipped.
 */
export async function enqueueVendorAdmissionReviewOnce(
  db: DrizzleClient,
  vendorId: string,
): Promise<string | null> {
  // Guard: skip if a PENDING job already exists for this vendor
  return llmJobsQ.enqueueVendorAdmissionReviewOnce(db, vendorId);
}
