/**
 * QueueHoldStore — pause / hold markers for WP-12.
 *
 * Holds live under switchboard/holds/<workerId>/<taskId>.json.
 * They are not Doorbell delivery messages and not doorbell-buffer events.
 */

import { promises as fs } from "node:fs";
import { join } from "node:path";

import { AtomicFile } from "../atomic/AtomicFile.ts";
import {
  SwitchboardPaths,
  sanitizePathSegment,
} from "../paths/SwitchboardPaths.ts";

export const QUEUE_HOLD_SCHEMA = "codeflowmu.queue-hold/v1" as const;

export interface QueueHoldRecord {
  schema: typeof QUEUE_HOLD_SCHEMA;
  taskId: string;
  workerId: string;
  pausedAt: string;
  pausedBy: string;
  pauseReason: string;
  doorbellId?: string;
}

export class QueueHoldStore {
  readonly #paths: SwitchboardPaths;

  constructor(paths: SwitchboardPaths) {
    this.#paths = paths;
  }

  holdsDir(workerId: string): string {
    const safe = sanitizePathSegment(workerId, "workerId");
    return join(this.#paths.root, "holds", safe);
  }

  holdFile(workerId: string, taskId: string): string {
    const safeTask = sanitizePathSegment(taskId, "taskId");
    return join(this.holdsDir(workerId), `${safeTask}.json`);
  }

  async pause(record: QueueHoldRecord): Promise<string> {
    const path = this.holdFile(record.workerId, record.taskId);
    await AtomicFile.writeJson(path, record);
    return path;
  }

  async resume(workerId: string, taskId: string): Promise<boolean> {
    const path = this.holdFile(workerId, taskId);
    try {
      await fs.unlink(path);
      return true;
    } catch {
      return false;
    }
  }

  async get(
    workerId: string,
    taskId: string,
  ): Promise<QueueHoldRecord | null> {
    const path = this.holdFile(workerId, taskId);
    try {
      return (await AtomicFile.readJson(path)) as QueueHoldRecord;
    } catch {
      return null;
    }
  }

  async list(workerId: string): Promise<QueueHoldRecord[]> {
    const dir = this.holdsDir(workerId);
    let names: string[] = [];
    try {
      names = await fs.readdir(dir);
    } catch {
      return [];
    }
    const out: QueueHoldRecord[] = [];
    for (const name of names.sort()) {
      if (!name.endsWith(".json") || name.includes(".tmp")) continue;
      try {
        out.push(
          (await AtomicFile.readJson(join(dir, name))) as QueueHoldRecord,
        );
      } catch {
        /* skip corrupt */
      }
    }
    return out;
  }

  async listAllWorkers(workerIds: string[]): Promise<QueueHoldRecord[]> {
    const out: QueueHoldRecord[] = [];
    for (const id of workerIds) {
      out.push(...(await this.list(id)));
    }
    return out;
  }
}
