export type QueueJobStatus =
  | 'queued'
  | 'running'
  | 'succeeded'
  | 'failed'
  | 'dead_letter'
  | 'cancelled';

export interface QueueJob<TPayload = unknown, TResult = unknown> {
  id: string;
  queueName: string;
  type: string;
  payload: TPayload;
  status: QueueJobStatus;
  attempts: number;
  maxAttempts: number;
  createdAt: string;
  scheduledAt: string;
  startedAt?: string;
  completedAt?: string;
  lastError?: string;
  result?: TResult;
  progress?: Record<string, unknown>;
  metadata?: Record<string, unknown>;
  leaseOwner?: string;
  leaseExpiresAt?: string;
  idempotencyKey?: string;
  productId?: string;
  userId?: string;
}

export interface EnqueueJobInput<TPayload = unknown> {
  id?: string;
  type: string;
  payload: TPayload;
  maxAttempts?: number;
  delayMs?: number;
  progress?: Record<string, unknown>;
  metadata?: Record<string, unknown>;
  idempotencyKey?: string;
  productId?: string;
  userId?: string;
}

export interface ListJobsOptions {
  limit?: number;
  status?: QueueJobStatus;
}

export interface QueueStore {
  enqueue<TPayload = unknown>(
    queueName: string,
    input: EnqueueJobInput<TPayload>
  ): Promise<QueueJob<TPayload>>;
  get<TPayload = unknown, TResult = unknown>(
    queueName: string,
    id: string
  ): Promise<QueueJob<TPayload, TResult> | undefined>;
  list<TPayload = unknown, TResult = unknown>(
    queueName: string,
    options?: ListJobsOptions
  ): Promise<Array<QueueJob<TPayload, TResult>>>;
  claimNext<TPayload = unknown, TResult = unknown>(
    queueName: string,
    workerId: string,
    leaseMs: number,
    now?: Date
  ): Promise<QueueJob<TPayload, TResult> | undefined>;
  patch<TPayload = unknown, TResult = unknown>(
    queueName: string,
    id: string,
    patch: Partial<QueueJob<TPayload, TResult>>
  ): Promise<QueueJob<TPayload, TResult> | undefined>;
  clear(queueName?: string): Promise<void>;
}

export interface WorkerContext<TPayload = unknown, TResult = unknown> {
  patch(patch: Partial<QueueJob<TPayload, TResult>>): Promise<void>;
  heartbeat(): Promise<void>;
}

export type QueueHandler<TPayload = unknown, TResult = unknown> = (
  job: QueueJob<TPayload, TResult>,
  context: WorkerContext<TPayload, TResult>
) => Promise<TResult>;

export interface QueueWorkerOptions<TPayload = unknown, TResult = unknown> {
  queueName: string;
  store: QueueStore;
  handler: QueueHandler<TPayload, TResult>;
  workerId?: string;
  pollIntervalMs?: number;
  leaseMs?: number;
  backoffMs?: number;
}
