/* eslint-disable import-x/extensions */
// Build-script driver: turn palette params into the two files an app imports.
// Node-only — call it from a script, never from app code.

import { mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import type { GenerateThemeResult } from "./generateTheme.ts";
import { generateTheme } from "./generateTheme.ts";
import type { AccentName, PaletteSpec } from "./paletteSpecs.ts";

const generatedHeader = "/* Generated by alouette writeTheme. DO NOT EDIT. */";

// Emitted the way a formatter would leave it — unquoted theme keys (hence the
// camelcase disable in the file header) and trailing commas — so a generated
// file never churns the first time the app runs prettier/oxfmt over it.
const serializeThemeVariables = (
  themeVariables: GenerateThemeResult["themeVariables"],
): string =>
  `{\n${Object.entries(themeVariables)
    .map(([theme, variables]) => {
      const entries = Object.entries(variables)
        .map(([name, value]) => `    "${name}": "${value}",`)
        .join("\n");
      return `  ${theme}: {\n${entries}\n  },`;
    })
    .join("\n")}\n}`;

const themeVariablesModule = (
  themeVariables: GenerateThemeResult["themeVariables"],
): string =>
  `${generatedHeader}
/* eslint-disable camelcase */
import type { ThemeVariablesMap } from "alouette";

/**
 * Resolved CSS-variable maps for every theme, paired with the generated palette
 * CSS. Pass to \`<AlouetteProvider themeVariables={...}>\`.
 */
export const themeVariables: ThemeVariablesMap = ${serializeThemeVariables(themeVariables)};
`;

export interface WriteThemeParams {
  /** Directory the files are written to, created if missing. */
  outDir: string;
  /**
   * Per-accent params merged over the alouette defaults, so only the accents
   * the app re-colors need to be listed. Omit to reproduce the default palette.
   */
  overrides?: Partial<Record<AccentName, PaletteSpec>>;
  /**
   * Skip the `oklch()` overlay entirely and ship sRGB hex on every platform.
   * @default false
   */
  srgbOnly?: boolean;
  cssFileName?: string;
  themeVariablesFileName?: string;
}

export interface WriteThemeResult {
  cssPath: string;
  /**
   * The wide-gamut overlay, named after `cssFileName` (`palette-oklch.css`).
   * `undefined` when `srgbOnly` is set.
   */
  oklchCssPath: string | undefined;
  themeVariablesPath: string;
}

/**
 * Generate an app's palette and write it to disk: the palette CSS to import
 * after `alouette/core.css`, and the `themeVariables` module to pass to
 * `<AlouetteProvider themeVariables={...}>`. Writing them from one call is what
 * keeps the className tokens and the JS token reads on the same colors.
 *
 * - `palette.css` (hex, complete on its own) + `palette-oklch.css`, imported
 *   after it only if the app wants display-p3 chroma on web.
 * - `themeVariables.ts` in sRGB hex, the only format native can parse. The map
 *   feeds native token reads only — web resolves every token from the CSS — so
 *   there is no oklch counterpart.
 */
export const writeTheme = ({
  outDir,
  overrides,
  srgbOnly = false,
  cssFileName = "palette.css",
  themeVariablesFileName = "themeVariables.ts",
}: WriteThemeParams): WriteThemeResult => {
  const { css, oklchCss, themeVariables } = generateTheme(overrides);

  mkdirSync(outDir, { recursive: true });

  const cssPath = join(outDir, cssFileName);
  writeFileSync(
    cssPath,
    `${generatedHeader}
/* App palette. Import after "alouette/core.css", instead of
   "alouette/global.css" — which carries alouette's default palette. */
${css}`,
  );

  const themeVariablesPath = join(outDir, themeVariablesFileName);
  writeFileSync(themeVariablesPath, themeVariablesModule(themeVariables));

  if (srgbOnly) {
    return { cssPath, oklchCssPath: undefined, themeVariablesPath };
  }

  const oklchCssPath = join(outDir, cssFileName.replace(/\.css$/, "-oklch$&"));
  writeFileSync(
    oklchCssPath,
    `${generatedHeader}
/* Wide-gamut half of the app palette. Optional — import after "${cssFileName}"
   to opt web into the display-p3 ramp. */
${oklchCss}`,
  );

  return { cssPath, oklchCssPath, themeVariablesPath };
};
