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

// src/features/gen-html/infrastructure/local-server/preview-url.ts
var LOCAL_SERVER_HOST = "127.0.0.1";
var LOCAL_SERVER_HEALTH_PATH = "/index.json";
new Set(
  builtinModules.flatMap((moduleName) => [moduleName, moduleName.replace(/^node:/, ""), `node:${moduleName.replace(/^node:/, "")}`])
);
function isRecord(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

// src/features/gen-html/infrastructure/local-server/health.ts
function getHealthUrl(port) {
  return `http://${LOCAL_SERVER_HOST}:${port}${LOCAL_SERVER_HEALTH_PATH}`;
}
function requestJson(url) {
  return new Promise((resolve) => {
    const request = http.get(url, { timeout: 2e3 }, (response) => {
      let body = "";
      response.setEncoding("utf8");
      response.on("data", (chunk) => {
        body += chunk;
      });
      response.on("end", () => {
        if (response.statusCode !== 200) {
          resolve(void 0);
          return;
        }
        try {
          resolve(JSON.parse(body));
        } catch {
          resolve(void 0);
        }
      });
    });
    request.on("timeout", () => {
      request.destroy();
      resolve(void 0);
    });
    request.on("error", () => {
      resolve(void 0);
    });
  });
}
function getLocalServerBaseUrl(port) {
  return `http://${LOCAL_SERVER_HOST}:${port}`;
}

// src/features/gen-html/infrastructure/local-server/preview-url.ts
var PREVIEW_STORY_INDEX_TIMEOUT_MS = 8e3;
var PREVIEW_STORY_INDEX_INTERVAL_MS = 400;
function normalizeSlashes(value) {
  return value.split(path.sep).join("/");
}
function wait(delayMs) {
  return new Promise((resolve) => {
    setTimeout(resolve, delayMs);
  });
}
function listStoryFiles(outputDirectory) {
  if (!fs.existsSync(outputDirectory) || !fs.statSync(outputDirectory).isDirectory()) {
    return [];
  }
  const storyFiles = [];
  const visitDirectory = (directoryPath) => {
    const entries = fs.readdirSync(directoryPath, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
    for (const entry of entries) {
      const entryPath = path.join(directoryPath, entry.name);
      if (entry.isDirectory()) {
        visitDirectory(entryPath);
        continue;
      }
      if (entry.isFile() && /\.stories\.[cm]?[jt]sx?$/i.test(entry.name)) {
        storyFiles.push(entryPath);
      }
    }
  };
  visitDirectory(outputDirectory);
  return storyFiles;
}
function selectPreviewStoryId(outputDirectory, index) {
  const entries = isRecord(index.entries) ? Object.values(index.entries) : [];
  const outputDirectoryName = path.basename(outputDirectory);
  const storyFileNames = listStoryFiles(outputDirectory).map((filePath) => normalizeSlashes(path.basename(filePath)));
  let selectedId = "";
  let selectedScore = -1;
  for (const entry of entries) {
    if (!isRecord(entry) || typeof entry.id !== "string" || !entry.id.trim()) {
      continue;
    }
    if (typeof entry.type === "string" && entry.type === "docs") {
      continue;
    }
    const importPath = typeof entry.importPath === "string" ? normalizeSlashes(entry.importPath) : "";
    const name = typeof entry.name === "string" ? entry.name : "";
    const matchesOutputDirectory = importPath.includes(`/${outputDirectoryName}/`);
    const matchesStoryFile = storyFileNames.some((fileName) => importPath.endsWith(`/${fileName}`) || importPath.includes(`/${fileName}`));
    let score = 0;
    if (!matchesOutputDirectory) {
      continue;
    }
    score += 5;
    if (matchesStoryFile) {
      score += 10;
    }
    if (entry.id.endsWith("--component-preview") || entry.id.endsWith("--componentpreview")) {
      score += 3;
    }
    if (name === "ComponentPreview" || name === "\uCEF4\uD3EC\uB10C\uD2B8 \uBBF8\uB9AC\uBCF4\uAE30") {
      score += 2;
    }
    if (score > selectedScore) {
      selectedId = entry.id;
      selectedScore = score;
    }
  }
  return selectedId;
}
function buildLocalServerPreviewUrl(baseUrl, storyId) {
  return storyId ? `${baseUrl}/?path=${encodeURIComponent(`/story/${storyId}`)}` : baseUrl;
}
async function waitForPreviewStoryId(outputDirectory, port, options = {}) {
  const timeoutMs = options.timeoutMs ?? PREVIEW_STORY_INDEX_TIMEOUT_MS;
  const intervalMs = options.intervalMs ?? PREVIEW_STORY_INDEX_INTERVAL_MS;
  const requestIndex = options.requestIndex ?? requestJson;
  const deadline = Date.now() + timeoutMs;
  const healthUrl = getHealthUrl(port);
  let storyId = "";
  do {
    const index = await requestIndex(healthUrl);
    storyId = index ? selectPreviewStoryId(outputDirectory, index) : "";
    if (storyId || Date.now() >= deadline) {
      return storyId;
    }
    await wait(intervalMs);
  } while (Date.now() < deadline);
  return storyId;
}
async function getLocalServerPreviewUrl(outputDirectory, port, options = {}) {
  const resolution = await resolveLocalServerPreviewUrl(outputDirectory, port, options);
  return resolution.previewUrl;
}
async function resolveLocalServerPreviewUrl(outputDirectory, port, options = {}) {
  const baseUrl = getLocalServerBaseUrl(port);
  const storyId = await waitForPreviewStoryId(outputDirectory, port, options);
  return {
    baseUrl,
    previewUrl: buildLocalServerPreviewUrl(baseUrl, storyId),
    storyFound: Boolean(storyId),
    storyId
  };
}

export { getLocalServerPreviewUrl, resolveLocalServerPreviewUrl, selectPreviewStoryId, waitForPreviewStoryId };
