/**
 * Netlify Edge bundle emitter.
 *
 * Runs as the last step of `mandu build --target=netlify-edge`. Produces:
 *
 *   netlify/edge-functions/ssr.ts — Netlify Edge Function entry (auto-detected)
 *   .mandu/netlify/register.ts    — SSR handler registration wiring
 *   .mandu/netlify/manifest.json  — cloned RoutesManifest
 *   netlify.toml                  — generated if absent; preserved otherwise
 *
 * Netlify deploys TypeScript directly (Deno under the hood), so no
 * pre-bundling step is needed. The entry file carries the `export const
 * config = { path: "/*" }` marker Netlify reads to scope this function to
 * all requests.
 */

import path from "path";
import fs from "fs/promises";
import { existsSync } from "fs";
import type { RoutesManifest } from "@mandujs/core";
import { generateNetlifyEdgeConfig } from "@mandujs/edge/netlify";
import { generateRegisterSource, inferProjectName } from "./edge-shared";

const NETLIFY_OUTPUT_DIR = ".mandu/netlify";
const NETLIFY_ENTRY_DIR = "netlify/edge-functions";
const NETLIFY_ENTRY_FILENAME = "ssr.ts";
const NETLIFY_REGISTER_FILENAME = "register.ts";
const NETLIFY_MANIFEST_FILENAME = "manifest.json";
const NETLIFY_CONFIG_FILENAME = "netlify.toml";

export interface EmitNetlifyEdgeBundleOptions {
  /** Absolute path to the project root. */
  rootDir: string;
  /** Parsed routes manifest — same object the main build consumed. */
  manifest: RoutesManifest;
  /** CSS link path (from the main build). Forwarded to the Netlify handler. */
  cssPath: string | false;
  /** Override the Netlify project name. Defaults to a slug of the package name. */
  projectName?: string;
}

export interface EmitNetlifyEdgeBundleResult {
  /** Absolute path to the generated netlify/edge-functions/ssr.ts. */
  edgeEntryPath: string;
  /** Whether netlify.toml was newly generated (vs preserved). */
  netlifyConfigGenerated: boolean;
  /** Absolute path to netlify.toml. */
  netlifyConfigPath: string;
}

export async function emitNetlifyEdgeBundle(
  options: EmitNetlifyEdgeBundleOptions
): Promise<EmitNetlifyEdgeBundleResult> {
  const { rootDir, manifest, cssPath, projectName: explicitName } = options;

  console.log(`\n🌐 Building Netlify Edge bundle...`);

  const outputDir = path.join(rootDir, NETLIFY_OUTPUT_DIR);
  const netlifyEntryDir = path.join(rootDir, NETLIFY_ENTRY_DIR);
  await fs.mkdir(outputDir, { recursive: true });
  await fs.mkdir(netlifyEntryDir, { recursive: true });

  // 1. Manifest copy under .mandu/netlify/.
  const manifestPath = path.join(outputDir, NETLIFY_MANIFEST_FILENAME);
  await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2));

  // 2. register.ts under .mandu/netlify/.
  const registerSource = generateRegisterSource(manifest, {
    targetLabel: "netlify-edge",
    rootDir,
    outputDir,
  });
  const registerPath = path.join(outputDir, NETLIFY_REGISTER_FILENAME);
  await fs.writeFile(registerPath, registerSource);

  // 3. netlify/edge-functions/ssr.ts — the Netlify-visible Edge Function.
  const edgeEntryPath = path.join(netlifyEntryDir, NETLIFY_ENTRY_FILENAME);
  const entrySource = generateNetlifyEdgeEntrySource({
    manifestRelativePath: relativeToEntry(netlifyEntryDir, manifestPath),
    registerRelativePath: relativeToEntry(netlifyEntryDir, registerPath),
    cssPath,
  });
  await fs.writeFile(edgeEntryPath, entrySource);

  // 4. Emit or preserve netlify.toml.
  const projectName =
    (explicitName ?? (await inferProjectName(rootDir))) || "mandu-netlify";
  const netlifyConfigPath = path.join(rootDir, NETLIFY_CONFIG_FILENAME);
  const netlifyConfigExists = existsSync(netlifyConfigPath);

  if (!netlifyConfigExists) {
    const toml = generateNetlifyEdgeConfig({
      projectName,
      functionPath: `${NETLIFY_ENTRY_DIR}/${NETLIFY_ENTRY_FILENAME}`,
      functionName: "ssr",
    });
    await fs.writeFile(netlifyConfigPath, toml);
  }

  console.log(`   ✅ netlify/edge-functions/${NETLIFY_ENTRY_FILENAME}`);
  console.log(`   📄 netlify.toml ${netlifyConfigExists ? "(preserved)" : "(generated)"}`);
  console.log(`   Output: ${NETLIFY_OUTPUT_DIR}/`);
  console.log(`\n   Next: netlify deploy   or   netlify dev`);

  return {
    edgeEntryPath,
    netlifyConfigGenerated: !netlifyConfigExists,
    netlifyConfigPath,
  };
}

/**
 * Generate `netlify/edge-functions/ssr.ts`. The `export const config`
 * marker Netlify reads uses `path: "/*"` by default — user `netlify.toml`
 * overrides win when present. The Deno Deploy runtime resolves
 * `import "npm:@mandujs/..."` against the registry at deploy time.
 */
function generateNetlifyEdgeEntrySource(opts: {
  manifestRelativePath: string;
  registerRelativePath: string;
  cssPath: string | false;
}): string {
  const cssPathExpr =
    opts.cssPath === false ? "false" : JSON.stringify(opts.cssPath);
  return [
    `// Auto-generated by mandu build --target=netlify-edge.`,
    `// Netlify Edge Function entry (Deno runtime).`,
    `import manifest from "${opts.manifestRelativePath}" with { type: "json" };`,
    `import { createNetlifyEdgeHandler } from "@mandujs/edge/netlify";`,
    `import "${opts.registerRelativePath}";`,
    ``,
    `const fetch = createNetlifyEdgeHandler(manifest as any, {`,
    `  cssPath: ${cssPathExpr},`,
    `});`,
    ``,
    `export default fetch;`,
    ``,
    `// Netlify reads the \`config\` export to scope this function. The`,
    `// netlify.toml [[edge_functions]] entry takes precedence when present.`,
    `export const config = { path: "/*" };`,
    ``,
  ].join("\n");
}

function relativeToEntry(entryDir: string, absPath: string): string {
  let rel = path.relative(entryDir, absPath).replace(/\\/g, "/");
  if (!rel.startsWith(".")) rel = `./${rel}`;
  return rel;
}
