import fs from 'node:fs';
import path from 'node:path';
import { builtinModules } from 'node:module';

// src/features/gen-html/infrastructure/local-server/lock.ts
var LOCAL_SERVER_LOCK_STALE_MS = 12e4;
new Set(
  builtinModules.flatMap((moduleName) => [moduleName, moduleName.replace(/^node:/, ""), `node:${moduleName.replace(/^node:/, "")}`])
);
function getLocalServerPaths(paths) {
  const directoryPath = path.join(paths.baseDir, "local-server");
  const generatedDirectoryPath = path.join(directoryPath, "generated");
  const multipleDirectoryPath = path.join(directoryPath, "multiple");
  const storybookConfigDirectoryPath = path.join(directoryPath, ".storybook");
  return {
    directoryPath,
    generatedDirectoryPath,
    generatedRegistryPath: path.join(directoryPath, "generated-registry.json"),
    multipleDirectoryPath,
    logPath: path.join(directoryPath, "server.log"),
    packageJsonPath: path.join(directoryPath, "package.json"),
    packageCustomJsonPath: path.join(directoryPath, "package-custom.json"),
    previewTargetPath: path.join(directoryPath, "preview-target.json"),
    refreshLockPath: path.join(directoryPath, "refresh.lock"),
    scssModuleDeclarationPath: path.join(directoryPath, "scss.d.ts"),
    serverLockPath: path.join(directoryPath, "server.lock"),
    statePath: path.join(directoryPath, "server-state.json"),
    storybookConfigDirectoryPath,
    storybookMainConfigPath: path.join(storybookConfigDirectoryPath, "main.ts"),
    storybookManagerConfigPath: path.join(storybookConfigDirectoryPath, "manager.tsx"),
    storybookPreviewConfigPath: path.join(storybookConfigDirectoryPath, "preview.ts"),
    tsconfigPath: path.join(directoryPath, "tsconfig.json")
  };
}

// src/features/gen-html/infrastructure/local-server/lock.ts
function wait(delayMs) {
  return new Promise((resolve) => {
    setTimeout(resolve, delayMs);
  });
}
function isStaleLock(lockPath, staleMs) {
  try {
    const stat = fs.statSync(lockPath);
    return Date.now() - stat.mtimeMs > staleMs;
  } catch {
    return false;
  }
}
function tryAcquireFileLock(options) {
  const record = {
    acquiredAt: (/* @__PURE__ */ new Date()).toISOString(),
    owner: options.owner,
    pid: process.pid
  };
  fs.mkdirSync(path.dirname(options.lockPath), { recursive: true });
  try {
    const fileDescriptor = fs.openSync(options.lockPath, "wx");
    fs.writeFileSync(fileDescriptor, `${JSON.stringify(record, null, 2)}
`, "utf8");
    fs.closeSync(fileDescriptor);
    options.trace("local-server:lock:acquired", `${options.owner} ${options.lockPath}`);
    return true;
  } catch {
    return false;
  }
}
async function withFileLock(options, task) {
  const staleMs = options.staleMs ?? LOCAL_SERVER_LOCK_STALE_MS;
  const timeoutMs = options.timeoutMs ?? staleMs;
  const startedAt = Date.now();
  while (!tryAcquireFileLock(options)) {
    if (isStaleLock(options.lockPath, staleMs)) {
      options.trace("local-server:lock:stale:remove", `${options.owner} ${options.lockPath}`);
      fs.rmSync(options.lockPath, { force: true });
      continue;
    }
    if (Date.now() - startedAt > timeoutMs) {
      throw new Error(`local-server \uB77D \uD68D\uB4DD \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. owner=${options.owner} lock=${options.lockPath}`);
    }
    options.trace("local-server:lock:wait", `${options.owner} ${options.lockPath}`);
    await wait(100);
  }
  try {
    return await task();
  } finally {
    fs.rmSync(options.lockPath, { force: true });
    options.trace("local-server:lock:released", `${options.owner} ${options.lockPath}`);
  }
}
function withLocalServerLock(paths, trace, owner, task) {
  return withFileLock(
    {
      lockPath: getLocalServerPaths(paths).serverLockPath,
      owner,
      trace
    },
    task
  );
}
function withLocalServerRefreshLock(paths, trace, owner, task) {
  return withFileLock(
    {
      lockPath: getLocalServerPaths(paths).refreshLockPath,
      owner,
      trace
    },
    task
  );
}

export { withFileLock, withLocalServerLock, withLocalServerRefreshLock };
