import { Job, PublishRequest } from "./types";

// In-memory only for the v1 prototype: jobs are lost on restart. Replace
// with a persistent store (sqlite/postgres) before relying on this for
// anything beyond local testing.
const jobs = new Map<string, Job>();

export class RequestConflictError extends Error {
  constructor(requestId: string) {
    super(`requestId "${requestId}" was already used with a different request body`);
    this.name = "RequestConflictError";
  }
}

function bodiesMatch(a: PublishRequest, b: PublishRequest): boolean {
  return JSON.stringify(a) === JSON.stringify(b);
}

// Returns the existing job if requestId was already seen with an identical
// body (idempotent retry), or creates+returns a fresh "processing" job.
// Throws RequestConflictError if requestId was seen with a different body.
export function getOrCreateJob(request: PublishRequest): { job: Job; isNew: boolean } {
  const existing = jobs.get(request.requestId);
  if (existing) {
    if (!bodiesMatch(existing.requestBody, request)) {
      throw new RequestConflictError(request.requestId);
    }
    return { job: existing, isNew: false };
  }

  const now = Date.now();
  const job: Job = {
    requestId: request.requestId,
    requestBody: request,
    status: "processing",
    createdAt: now,
    updatedAt: now,
  };
  jobs.set(request.requestId, job);
  return { job, isNew: true };
}

export function getJob(requestId: string): Job | undefined {
  return jobs.get(requestId);
}

export function updateJob(requestId: string, patch: Partial<Job>): Job {
  const job = jobs.get(requestId);
  if (!job) {
    throw new Error(`updateJob called for unknown requestId "${requestId}"`);
  }
  Object.assign(job, patch, { updatedAt: Date.now() });
  return job;
}
