import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
import { dirname } from "node:path";

export class UltragoalStateError extends Error {
  constructor(message, status = 65) {
    super(message);
    this.name = "UltragoalStateError";
    this.status = status;
  }
}

export const readUltragoalState = (path, fallback = {}) => {
  if (!existsSync(path)) return fallback;
  try {
    return JSON.parse(readFileSync(path, "utf8"));
  } catch {
    throw new UltragoalStateError("corrupt ultragoal state");
  }
};

export const writeUltragoalState = (path, state) => {
  mkdirSync(dirname(path), { recursive: true });
  const tmpPath = `${path}.${process.pid}.${Date.now()}.tmp`;
  writeFileSync(tmpPath, `${JSON.stringify(state, null, 2)}\n`);
  renameSync(tmpPath, path);
};

const sleepSync = (milliseconds) => {
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
};

export const withUltragoalLock = (lockDir, fn) => {
  mkdirSync(dirname(lockDir), { recursive: true });
  const startedAt = Date.now();
  while (true) {
    try {
      mkdirSync(lockDir, { recursive: false });
      break;
    } catch (error) {
      if (Date.now() - startedAt > 5000) {
        throw new UltragoalStateError("ultragoal state lock timed out");
      }
      sleepSync(20);
    }
  }

  try {
    return fn();
  } finally {
    rmSync(lockDir, { recursive: true, force: true });
  }
};
