import { eq, and, inArray, asc, desc } from 'drizzle-orm';

const TERMINAL_STATUSES = ['completed', 'failed', 'stopped', 'interrupted'] as const;
import { db } from '../db';
import { pipelineJobs } from './schema';
import type { PipelineJobInsert } from '../types';

export async function createPipelineJob(data: PipelineJobInsert) {
  const rows = await db.insert(pipelineJobs).values(data).returning();
  return rows[0]!;
}

export async function getPipelineJob(id: string) {
  const rows = await db.select().from(pipelineJobs).where(eq(pipelineJobs.id, id)).limit(1);
  return rows[0] ?? null;
}

export async function updatePipelineJob(id: string, data: Partial<PipelineJobInsert>) {
  await db.update(pipelineJobs).set(data).where(eq(pipelineJobs.id, id));
}

export async function getPipelineJobsForUser(userId: number, limit = 50) {
  return db
    .select()
    .from(pipelineJobs)
    .where(eq(pipelineJobs.userId, userId))
    .orderBy(desc(pipelineJobs.createdAt))
    .limit(limit);
}

// Delete a single job row.
export async function deletePipelineJob(id: string) {
  await db.delete(pipelineJobs).where(eq(pipelineJobs.id, id));
}

// Delete all of a user's finished jobs (history); returns the deleted ids so their logs can be removed.
export async function deleteTerminalJobsForUser(userId: number) {
  const rows = await db
    .delete(pipelineJobs)
    .where(and(eq(pipelineJobs.userId, userId), inArray(pipelineJobs.status, [...TERMINAL_STATUSES])))
    .returning({ id: pipelineJobs.id });
  return rows.map((r) => r.id);
}

// Count of the user's queued (pending) jobs — for the header badge.
export async function countPendingJobs(userId: number) {
  const rows = await db
    .select({ id: pipelineJobs.id })
    .from(pipelineJobs)
    .where(and(eq(pipelineJobs.userId, userId), eq(pipelineJobs.status, 'pending')));
  return rows.length;
}

// Oldest queued job across everything (single-user → global queue). Used to promote the next job.
export async function getOldestPendingJob() {
  const rows = await db
    .select()
    .from(pipelineJobs)
    .where(eq(pipelineJobs.status, 'pending'))
    .orderBy(asc(pipelineJobs.createdAt))
    .limit(1);
  return rows[0] ?? null;
}

// All queued jobs, oldest first — used to fill each execution lane (download vs agentic) independently.
export async function getPendingJobs() {
  return db.select().from(pipelineJobs).where(eq(pipelineJobs.status, 'pending')).orderBy(asc(pipelineJobs.createdAt));
}

// On restart, only RUNNING jobs are orphaned (their process died) → interrupted. PENDING jobs are the
// queue backlog and must survive to be promoted after startup.
export async function markInterruptedJobs() {
  const result = await db
    .update(pipelineJobs)
    .set({ status: 'interrupted', completedAt: new Date() })
    .where(eq(pipelineJobs.status, 'running'))
    .returning({ id: pipelineJobs.id });
  return result.length;
}
