import { spawnSync } from 'node:child_process';
import fs2 from 'node:fs';
import path from 'node:path';
import { inspect } from 'node:util';
import { builtinModules } from 'node:module';

// src/features/gen-html/infrastructure/local-server/dependencies/installer.ts
function stringifyUnknown(value) {
  if (value === void 0 || value === null) {
    return "";
  }
  if (typeof value === "string") {
    return value;
  }
  if (Buffer.isBuffer(value)) {
    return value.toString("utf8");
  }
  if (value instanceof Error) {
    return value.stack || value.message;
  }
  return inspect(value, { depth: 6, breakLength: 120 });
}
function getErrorSummary(error) {
  if (error instanceof Error) {
    return `${error.name}: ${error.message}`;
  }
  return stringifyUnknown(error) || "Unknown error";
}
var LOCAL_SERVER_LEGACY_FILE_NAMES = ["server.mjs"];
var LOCAL_SERVER_STYLE_EXPORT_FILE_PATTERN = /\.(?:css|s[ac]ss)$/i;
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")
  };
}
function isRecord(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
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);
}

// src/features/gen-html/infrastructure/local-server/dependencies/manifest.ts
function normalizeDependencies(value) {
  if (!isRecord(value)) {
    return {};
  }
  return Object.entries(value).reduce((accumulator, [key, dependencyValue]) => {
    if (typeof dependencyValue === "string" && dependencyValue.trim()) {
      accumulator[key] = dependencyValue;
    }
    return accumulator;
  }, {});
}
function resolveLocalServerStyleExportTarget(value) {
  if (typeof value === "string") {
    return LOCAL_SERVER_STYLE_EXPORT_FILE_PATTERN.test(value) ? value : "";
  }
  if (Array.isArray(value)) {
    for (const entry of value) {
      const resolvedTarget = resolveLocalServerStyleExportTarget(entry);
      if (resolvedTarget) {
        return resolvedTarget;
      }
    }
    return "";
  }
  if (isRecord(value)) {
    return resolveLocalServerStyleExportTarget(value.default) || resolveLocalServerStyleExportTarget(value.import) || resolveLocalServerStyleExportTarget(value.require);
  }
  return "";
}
function buildLocalServerStyleExportBridgeContent(bridgeFilePath, targetFilePath) {
  const relativeTargetPath = path.relative(path.dirname(bridgeFilePath), targetFilePath).split(path.sep).join("/");
  const normalizedTargetPath = relativeTargetPath.startsWith(".") ? relativeTargetPath : `./${relativeTargetPath}`;
  if (path.extname(targetFilePath).toLowerCase() === ".css") {
    return `@import '${normalizedTargetPath}';
`;
  }
  return `@forward '${normalizedTargetPath}';
`;
}
function synchronizeLocalServerStyleExportBridges(paths, trace) {
  const { directoryPath, packageJsonPath } = getLocalServerPaths(paths);
  const localServerPackageJson = readJsonFile(packageJsonPath);
  const dependencyNames = Object.keys(normalizeDependencies(localServerPackageJson?.dependencies));
  for (const dependencyName of dependencyNames) {
    const dependencyDirectoryPath = path.join(directoryPath, "node_modules", ...dependencyName.split("/"));
    const dependencyPackageJsonPath = path.join(dependencyDirectoryPath, "package.json");
    const dependencyPackageJson = readJsonFile(dependencyPackageJsonPath);
    const dependencyExports = isRecord(dependencyPackageJson?.exports) ? dependencyPackageJson.exports : {};
    for (const [exportKey, exportValue] of Object.entries(dependencyExports)) {
      if (!exportKey.startsWith("./")) {
        continue;
      }
      const exportTargetPath = resolveLocalServerStyleExportTarget(exportValue);
      if (!exportTargetPath) {
        continue;
      }
      const exportSubpath = exportKey.slice(2);
      if (!exportSubpath) {
        continue;
      }
      const targetFilePath = path.resolve(dependencyDirectoryPath, exportTargetPath);
      if (!fs2.existsSync(targetFilePath) || !fs2.statSync(targetFilePath).isFile()) {
        trace("local-server:style-export-bridge:missing-target", `${dependencyName} ${exportKey} -> ${targetFilePath}`);
        continue;
      }
      const bridgeFilePath = path.join(
        dependencyDirectoryPath,
        ...exportSubpath.split("/").filter(Boolean)
      ) + path.extname(targetFilePath);
      const bridgeContent = buildLocalServerStyleExportBridgeContent(bridgeFilePath, targetFilePath);
      const currentBridgeContent = fs2.existsSync(bridgeFilePath) ? fs2.readFileSync(bridgeFilePath, "utf8") : "";
      if (currentBridgeContent === bridgeContent) {
        continue;
      }
      fs2.mkdirSync(path.dirname(bridgeFilePath), { recursive: true });
      fs2.writeFileSync(bridgeFilePath, bridgeContent, "utf8");
      trace("local-server:style-export-bridge:written", `${dependencyName} ${exportKey} -> ${bridgeFilePath}`);
    }
  }
}

// src/features/gen-html/infrastructure/local-server/dependencies/installer.ts
var LOCAL_SERVER_NPM_INSTALL_ARGS = ["install", "--legacy-peer-deps", "--no-audit", "--no-fund"];
function hasAllLocalServerDependencies(directoryPath) {
  const packageJsonPath = path.join(directoryPath, "package.json");
  const packageJson = readJsonFile(packageJsonPath);
  const dependencies = Object.keys(normalizeDependencies(packageJson?.dependencies));
  if (dependencies.length === 0) {
    return true;
  }
  return dependencies.every((dependencyName) => fs2.existsSync(path.join(directoryPath, "node_modules", ...dependencyName.split("/"))));
}
function installLocalServerDependencies(directoryPath, trace) {
  trace("local-server:install:start", `${directoryPath} :: npm ${LOCAL_SERVER_NPM_INSTALL_ARGS.join(" ")}`);
  const result = spawnSync("npm", [...LOCAL_SERVER_NPM_INSTALL_ARGS], {
    cwd: directoryPath,
    encoding: "utf8",
    maxBuffer: 1024 * 1024 * 20,
    stdio: "inherit"
  });
  if (result.error || result.status !== 0) {
    trace("local-server:install:failed", getErrorSummary(result.error || result.stderr || result.status));
    throw new Error("\uB85C\uCEEC \uD504\uB9AC\uBDF0 \uC11C\uBC84 \uC758\uC874\uC131 \uC124\uCE58\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
  }
  trace("local-server:install:done", directoryPath);
}
function ensureLocalServerDependencies(paths, trace, forceInstall = false) {
  const { directoryPath } = getLocalServerPaths(paths);
  const nodeModulesPath = path.join(directoryPath, "node_modules");
  const hasNodeModules = fs2.existsSync(nodeModulesPath);
  const hasRequiredDependencies = hasNodeModules ? hasAllLocalServerDependencies(directoryPath) : false;
  const shouldInstall = forceInstall || !hasNodeModules || !hasRequiredDependencies;
  if (hasNodeModules && !hasRequiredDependencies) {
    trace("local-server:install:repair", directoryPath);
  }
  if (shouldInstall) {
    installLocalServerDependencies(directoryPath, trace);
  }
  synchronizeLocalServerStyleExportBridges(paths, trace);
}
function removeLegacyLocalServerFiles(localServerPaths, trace) {
  for (const fileName of LOCAL_SERVER_LEGACY_FILE_NAMES) {
    const targetPath = path.join(localServerPaths.directoryPath, fileName);
    if (!fs2.existsSync(targetPath)) {
      continue;
    }
    fs2.unlinkSync(targetPath);
    trace("local-server:cleanup:legacy-file", targetPath);
  }
}

export { ensureLocalServerDependencies, hasAllLocalServerDependencies, installLocalServerDependencies, removeLegacyLocalServerFiles };
