import { promises } from 'node:fs';
import { e as getModulePaths, f as defu, d as relative, j as join, i as isAbsolute, r as resolve, h as getNearestPackage } from './cli.bf96fb69.mjs';
import 'events';
import 'fs';
import 'path';
import 'util';
import 'stream';
import 'os';
import 'node:module';
import 'node:url';
import 'node:fs/promises';
import 'node:os';
import 'crypto';
import 'module';
import 'perf_hooks';
import 'vm';
import 'url';
import 'assert';
import 'buffer';
import 'tty';
import 'node:path';
import 'constants';
import 'net';
import 'child_process';

const writeTypes = async (remix) => {
  const modulePaths = getModulePaths(remix.options.modulesDir);
  const tsConfig = defu(remix.options.typescript?.tsConfig, {
    compilerOptions: {
      jsx: "preserve",
      target: "ESNext",
      module: "ESNext",
      moduleResolution: "Node",
      skipLibCheck: true,
      strict: remix.options.typescript?.strict ?? false,
      allowJs: true,
      noEmit: true,
      resolveJsonModule: true,
      allowSyntheticDefaultImports: true,
      types: ["node"],
      baseUrl: relative(remix.options.buildDir, remix.options.rootDir),
      paths: {}
    },
    include: [
      "./remix.d.ts",
      join(relative(remix.options.buildDir, remix.options.rootDir), "**/*"),
      ...remix.options.srcDir !== remix.options.rootDir ? [join(relative(remix.options.buildDir, remix.options.srcDir), "**/*")] : [],
      ...remix.options.typescript.includeWorkspace && remix.options.workspaceDir !== remix.options.rootDir ? [join(relative(remix.options.buildDir, remix.options.workspaceDir), "**/*")] : []
    ],
    exclude: []
  });
  const aliases = {
    ...remix.options.alias,
    "#build": remix.options.buildDir
  };
  for (const alias in aliases) {
    const relativePath = isAbsolute(aliases[alias]) ? relative(remix.options.rootDir, aliases[alias]) || "." : aliases[alias];
    const stats = await promises.stat(resolve(remix.options.rootDir, relativePath)).catch(() => null);
    tsConfig.compilerOptions = tsConfig.compilerOptions || {};
    if (stats?.isDirectory()) {
      tsConfig.compilerOptions.paths[alias] = [relativePath];
      tsConfig.compilerOptions.paths[`${alias}/*`] = [`${relativePath}/*`];
    } else {
      tsConfig.compilerOptions.paths[alias] = [relativePath.replace(/(?<=\w)\.\w+$/g, "")];
    }
  }
  const references = [
    ...remix.options.modules,
    ...remix.options._modules
  ].filter((f) => typeof f === "string").map((id) => ({ types: getNearestPackage(id, modulePaths)?.name || id }));
  const declarations = [];
  await remix.callHook("prepare:types", { references, declarations, tsConfig });
  const declaration = [
    ...references.map((ref) => {
      if ("path" in ref && isAbsolute(ref.path)) {
        ref.path = relative(remix.options.buildDir, ref.path);
      }
      return `/// <reference ${renderAttrs(ref)} />`;
    }),
    ...declarations,
    "",
    "export {}",
    ""
  ].join("\n");
  async function writeFile() {
    const GeneratedBy = "// Generated by Remix";
    const tsConfigPath = resolve(remix.options.buildDir, "tsconfig.json");
    await promises.mkdir(remix.options.buildDir, { recursive: true });
    await promises.writeFile(tsConfigPath, GeneratedBy + "\n" + JSON.stringify(tsConfig, null, 2));
    const declarationPath = resolve(remix.options.buildDir, "remix.d.ts");
    await promises.writeFile(declarationPath, GeneratedBy + "\n" + declaration);
  }
  await writeFile();
};
function renderAttrs(obj) {
  return Object.entries(obj).map((e) => renderAttr(e[0], e[1])).join(" ");
}
function renderAttr(key, value) {
  return value ? `${key}="${value}"` : "";
}

export { writeTypes as w };
