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

// src/features/gen-html/infrastructure/local-server/registry.ts
function normalizeOutputRelativePath(outputDirectory, filePath) {
  return path3.relative(outputDirectory, filePath).split(path3.sep).join("/");
}

// src/features/gen-html/domain/storybook.ts
var STORY_FILE_PATTERN = /\.stories\.[cm]?[jt]sx?$/i;
function isGenHtmlStoryFilePath(filePath) {
  return STORY_FILE_PATTERN.test(filePath);
}

// src/features/gen-html/infrastructure/runtime.ts
function listOutputFiles(outputDirectory) {
  if (!fs2.existsSync(outputDirectory) || !fs2.statSync(outputDirectory).isDirectory()) {
    return [];
  }
  const files = [];
  const visitDirectory = (directoryPath) => {
    const entries = fs2.readdirSync(directoryPath, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
    for (const entry of entries) {
      const entryPath = path3.join(directoryPath, entry.name);
      if (entry.isDirectory()) {
        visitDirectory(entryPath);
        continue;
      }
      if (entry.isFile()) {
        files.push(normalizeOutputRelativePath(outputDirectory, entryPath));
      }
    }
  };
  visitDirectory(outputDirectory);
  return files.sort((left, right) => left.localeCompare(right));
}
function isGenHtmlPreviewDirectoryCandidate(outputDirectory) {
  return listOutputFiles(outputDirectory).some((filePath) => isGenHtmlStoryFilePath(filePath));
}
var LOCAL_SERVER_SASS_VERSION = "^1.86.3";
var LOCAL_SERVER_REACT_QUERY_VERSION = "^5.81.2";
var LOCAL_SERVER_TYPES_NODE_VERSION = "^25.0.10";
var LOCAL_SERVER_TYPES_REACT_VERSION = "19.1.0";
var LOCAL_SERVER_TYPES_REACT_DOM_VERSION = "19.1.1";
var LOCAL_SERVER_TYPESCRIPT_VERSION = "5.8.2";
var LOCAL_SERVER_VITE_VERSION = "^6.3.1";
var STORYBOOK_VERSION = "8.6.14";
var IMPORT_SPECIFIER_PATTERN = /\b(?:import|export)\s+(?:type\s+)?(?:[^'"`]*?\s+from\s*)?['"]([^'"`]+)['"]|\bimport\s*\(\s*['"]([^'"`]+)['"]\s*\)/g;
var SOURCE_FILE_EXTENSION_PATTERN = /\.[cm]?[jt]sx?$/i;
var NODE_BUILTIN_MODULE_NAMES = new Set(
  builtinModules.flatMap((moduleName) => [moduleName, moduleName.replace(/^node:/, ""), `node:${moduleName.replace(/^node:/, "")}`])
);
var LOCAL_SERVER_DEFAULT_PACKAGE_JSON = {
  dependencies: {
    "@types/node": LOCAL_SERVER_TYPES_NODE_VERSION,
    "@types/react": LOCAL_SERVER_TYPES_REACT_VERSION,
    "@types/react-dom": LOCAL_SERVER_TYPES_REACT_DOM_VERSION,
    "@tanstack/react-query": LOCAL_SERVER_REACT_QUERY_VERSION,
    "@storybook/addon-essentials": STORYBOOK_VERSION,
    "@storybook/react": STORYBOOK_VERSION,
    "@storybook/react-vite": STORYBOOK_VERSION,
    react: "^19.1.0",
    "react-dom": "^19.1.0",
    sass: LOCAL_SERVER_SASS_VERSION,
    storybook: STORYBOOK_VERSION,
    typescript: LOCAL_SERVER_TYPESCRIPT_VERSION,
    vite: LOCAL_SERVER_VITE_VERSION
  }};
function getLocalServerPaths(paths) {
  const directoryPath = path3.join(paths.baseDir, "local-server");
  const generatedDirectoryPath = path3.join(directoryPath, "generated");
  const multipleDirectoryPath = path3.join(directoryPath, "multiple");
  const storybookConfigDirectoryPath = path3.join(directoryPath, ".storybook");
  return {
    directoryPath,
    generatedDirectoryPath,
    generatedRegistryPath: path3.join(directoryPath, "generated-registry.json"),
    multipleDirectoryPath,
    logPath: path3.join(directoryPath, "server.log"),
    packageJsonPath: path3.join(directoryPath, "package.json"),
    packageCustomJsonPath: path3.join(directoryPath, "package-custom.json"),
    previewTargetPath: path3.join(directoryPath, "preview-target.json"),
    refreshLockPath: path3.join(directoryPath, "refresh.lock"),
    scssModuleDeclarationPath: path3.join(directoryPath, "scss.d.ts"),
    serverLockPath: path3.join(directoryPath, "server.lock"),
    statePath: path3.join(directoryPath, "server-state.json"),
    storybookConfigDirectoryPath,
    storybookMainConfigPath: path3.join(storybookConfigDirectoryPath, "main.ts"),
    storybookManagerConfigPath: path3.join(storybookConfigDirectoryPath, "manager.tsx"),
    storybookPreviewConfigPath: path3.join(storybookConfigDirectoryPath, "preview.ts"),
    tsconfigPath: path3.join(directoryPath, "tsconfig.json")
  };
}
function readJsonFile(filePath) {
  if (!fs2.existsSync(filePath)) {
    return void 0;
  }
  const raw = fs2.readFileSync(filePath, "utf8").trim();
  if (!raw) {
    return void 0;
  }
  return JSON.parse(raw);
}
function writeJsonFile(filePath, value) {
  fs2.mkdirSync(path3.dirname(filePath), { recursive: true });
  fs2.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}
`, "utf8");
}

// src/features/gen-html/infrastructure/local-server/dependencies/generated-output.ts
function isBareImportSpecifier(specifier) {
  return Boolean(specifier) && !specifier.startsWith(".") && !specifier.startsWith("/") && !specifier.includes("://") && !specifier.startsWith("\0");
}
function getPackageNameFromImportSpecifier(specifier) {
  if (!isBareImportSpecifier(specifier) || NODE_BUILTIN_MODULE_NAMES.has(specifier)) {
    return "";
  }
  if (specifier.startsWith("@")) {
    const [scope, name] = specifier.split("/");
    return scope && name ? `${scope}/${name}` : "";
  }
  return specifier.split("/")[0] || "";
}
function listSourceFiles(directoryPath) {
  if (!fs2.existsSync(directoryPath) || !fs2.statSync(directoryPath).isDirectory()) {
    return [];
  }
  const collected = [];
  const queue = [directoryPath];
  while (queue.length > 0) {
    const currentDirectoryPath = queue.pop();
    if (!currentDirectoryPath) {
      continue;
    }
    for (const entry of fs2.readdirSync(currentDirectoryPath, { withFileTypes: true })) {
      const entryPath = path3.join(currentDirectoryPath, entry.name);
      if (entry.isDirectory()) {
        queue.push(entryPath);
        continue;
      }
      if (entry.isFile() && SOURCE_FILE_EXTENSION_PATTERN.test(entry.name)) {
        collected.push(entryPath);
      }
    }
  }
  return collected.sort((left, right) => left.localeCompare(right));
}
function isBundledLocalServerDependency(packageName) {
  return Object.prototype.hasOwnProperty.call(LOCAL_SERVER_DEFAULT_PACKAGE_JSON.dependencies, packageName);
}
function collectOutputDependencyNames(outputDirectory) {
  const packageNames = /* @__PURE__ */ new Set();
  for (const filePath of listSourceFiles(outputDirectory)) {
    const source = fs2.readFileSync(filePath, "utf8");
    let match = IMPORT_SPECIFIER_PATTERN.exec(source);
    while (match) {
      const packageName = getPackageNameFromImportSpecifier(match[1] || match[2] || "");
      if (packageName && !isBundledLocalServerDependency(packageName)) {
        packageNames.add(packageName);
      }
      match = IMPORT_SPECIFIER_PATTERN.exec(source);
    }
    IMPORT_SPECIFIER_PATTERN.lastIndex = 0;
  }
  return [...packageNames].sort((left, right) => left.localeCompare(right));
}

// src/features/gen-html/infrastructure/local-server/registry.ts
function normalizeOutputDirectory(outputDirectory) {
  return path3.resolve(outputDirectory);
}
function createDependencyFingerprint(dependencyNames) {
  return dependencyNames.join("|");
}
function listGeneratedOutputDirectories(paths) {
  const { generatedDirectoryPath } = getLocalServerPaths(paths);
  if (!fs2.existsSync(generatedDirectoryPath) || !fs2.statSync(generatedDirectoryPath).isDirectory()) {
    return [];
  }
  return fs2.readdirSync(generatedDirectoryPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path3.join(generatedDirectoryPath, entry.name)).sort((left, right) => left.localeCompare(right));
}
function createRegistryEntry(outputDirectory, componentName = "") {
  const dependencyNames = collectOutputDependencyNames(outputDirectory);
  const normalizedOutputDirectory = normalizeOutputDirectory(outputDirectory);
  return {
    componentName: componentName || path3.basename(normalizedOutputDirectory),
    dependencyFingerprint: createDependencyFingerprint(dependencyNames),
    dependencyNames,
    outputDirectory: normalizedOutputDirectory,
    previewEligible: isGenHtmlPreviewDirectoryCandidate(normalizedOutputDirectory),
    updatedAt: (/* @__PURE__ */ new Date()).toISOString()
  };
}
function readGeneratedOutputRegistry(paths) {
  try {
    const registry = readJsonFile(getLocalServerPaths(paths).generatedRegistryPath);
    const entries = Array.isArray(registry?.entries) ? registry.entries.filter((entry) => typeof entry.outputDirectory === "string" && entry.outputDirectory.trim()) : [];
    return {
      entries,
      version: 1
    };
  } catch {
    return {
      entries: [],
      version: 1
    };
  }
}
function writeGeneratedOutputRegistry(paths, registry) {
  writeJsonFile(getLocalServerPaths(paths).generatedRegistryPath, {
    entries: registry.entries.sort((left, right) => left.outputDirectory.localeCompare(right.outputDirectory)),
    version: 1
  });
}
function upsertGeneratedOutputRegistryEntry(options) {
  const registry = readGeneratedOutputRegistry(options.paths);
  const nextEntry = createRegistryEntry(options.outputDirectory, options.componentName);
  const entries = registry.entries.filter(
    (entry) => normalizeOutputDirectory(entry.outputDirectory) !== nextEntry.outputDirectory
  );
  entries.push(nextEntry);
  writeGeneratedOutputRegistry(options.paths, {
    entries});
  options.trace(
    "local-server:registry:upsert",
    `component=${nextEntry.componentName} dependencies=${nextEntry.dependencyNames.length} preview=${nextEntry.previewEligible}`
  );
  return nextEntry;
}
function syncGeneratedOutputRegistryFromDisk(paths, trace) {
  const existingRegistry = readGeneratedOutputRegistry(paths);
  const existingNames = new Map(
    existingRegistry.entries.map((entry) => [normalizeOutputDirectory(entry.outputDirectory), entry.componentName])
  );
  const entries = listGeneratedOutputDirectories(paths).map(
    (outputDirectory) => createRegistryEntry(outputDirectory, existingNames.get(normalizeOutputDirectory(outputDirectory)) || "")
  );
  const registry = {
    entries,
    version: 1
  };
  writeGeneratedOutputRegistry(paths, registry);
  trace("local-server:registry:sync", `entries=${entries.length}`);
  return registry;
}
function listPreviewEligibleOutputDirectories(registry) {
  return registry.entries.filter((entry) => entry.previewEligible).map((entry) => entry.outputDirectory).sort((left, right) => left.localeCompare(right));
}

export { listPreviewEligibleOutputDirectories, readGeneratedOutputRegistry, syncGeneratedOutputRegistryFromDisk, upsertGeneratedOutputRegistryEntry, writeGeneratedOutputRegistry };
