/**
 * Low-level DB helpers for the AI job runner.
 *
 * Isolated so runner.ts stays thin and each helper is independently testable.
 * All helpers work on the llm_jobs table.
 */
import { eq } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client.js';
import { llmJobs } from '@/server/db/schema.js';
import * as llmJobsQ from '@/server/db/queries/llm-jobs.js';
import type { LlmJobRow, JobCompletionMeta } from '@/server/ai/kinds/types.js';

// ─── loadJobRow ───────────────────────────────────────────────────────────────

/** Fetch a single llm_jobs row. Returns null if not found. */
export async function loadJobRow(db: DrizzleClient, jobId: string): Promise<LlmJobRow | null> {
  const rows = await db
    .select({
      id: llmJobs.id,
      jobType: llmJobs.jobType,
      status: llmJobs.status,
      retryCount: llmJobs.retryCount,
      targetId: llmJobs.targetId,
      targetType: llmJobs.targetType,
      inputPayload: llmJobs.inputPayload,
      outputPayload: llmJobs.outputPayload,
      queueChainOverride: llmJobs.queueChainOverride,
    })
    .from(llmJobs)
    .where(eq(llmJobs.id, jobId))
    .limit(1);
  return rows[0] ?? null;
}

// ─── transitionToRunning ──────────────────────────────────────────────────────

/**
 * Status-guarded UPDATE: sets status='RUNNING' only when current status='PENDING'.
 * Returns true if row was updated (this runner won the race), false if another
 * runner already claimed it.
 */
export async function transitionToRunning(db: DrizzleClient, jobId: string): Promise<boolean> {
  return llmJobsQ.claim(db, jobId);
}

// ─── markJobFailed ────────────────────────────────────────────────────────────

/** terminal=true (default) stamps completed_at so the Step-2 backstop SKIPS it (deterministic failure — retry would be identical). terminal=false leaves completed_at NULL so Step-2 retries/escalates (transient infra failure that may recover). */
export async function markJobFailed(
  db: DrizzleClient,
  jobId: string,
  error: string,
  opts: { terminal?: boolean } = {},
): Promise<void> {
  const terminal = opts.terminal ?? true;
  await llmJobsQ.fail(db, jobId, error, terminal);
}

// ─── markJobCompleted ─────────────────────────────────────────────────────────

/** Mark job as COMPLETED with output_payload, completedAt timestamp, and optional cost/usage meta. */
export async function markJobCompleted(
  db: DrizzleClient,
  jobId: string,
  result: unknown,
  meta?: JobCompletionMeta,
): Promise<void> {
  await llmJobsQ.complete(db, jobId, result, meta);
}
