/**
 * CSS Generator for Kumo Themes
 *
 * Generates theme CSS files from the centralized config.
 * Outputs:
 * - theme-kumo.css: Base theme with all tokens
 * - theme-fedramp.css: Override layer for fedramp theme
 * - (future themes as needed)
 */

import { THEME_CONFIG, AVAILABLE_THEMES } from "./config.js";
import type { ThemeConfig, GeneratorOptions, TokenRenameMap } from "./types.js";

/**
 * Header comment for generated CSS files
 */
const GENERATED_FILE_HEADER = `/**
 * AUTO-GENERATED FILE - DO NOT EDIT DIRECTLY
 *
 * This file is generated by the theme generator.
 * To modify tokens, edit: scripts/theme-generator/config.ts
 * Then run: pnpm codegen:themes
 */

`;

/**
 * Generate a light-dark() CSS function call
 */
function lightDark(light: string, dark: string): string {
  return `light-dark(\n    ${light},\n    ${dark}\n  )`;
}

function pushModeScopedBaseVariables(
  lines: string[],
  config: ThemeConfig,
  themeName: string,
  useNewNames: boolean,
  options: {
    wrapInBaseLayer?: boolean;
  } = {},
): void {
  const textEntries: Array<{ name: string; light: string; dark: string }> = [];
  const colorEntries: Array<{ name: string; light: string; dark: string }> = [];

  for (const [tokenName, def] of Object.entries(config.text)) {
    const themeColors = def.theme[themeName];
    if (!themeColors) continue;
    const name = useNewNames ? def.newName : tokenName;
    textEntries.push({
      name,
      light: themeColors.light,
      dark: themeColors.dark,
    });
  }

  for (const [tokenName, def] of Object.entries(config.color)) {
    const themeColors = def.theme[themeName];
    if (!themeColors) continue;
    const name = useNewNames ? def.newName : tokenName;
    colorEntries.push({
      name,
      light: themeColors.light,
      dark: themeColors.dark,
    });
  }

  if (textEntries.length === 0 && colorEntries.length === 0) {
    return;
  }

  const themeSelector = `[data-theme="${themeName}"]`;
  const lightSelector =
    themeName === "kumo" ? `:root, ${themeSelector}` : `${themeSelector}`;
  const darkSelector =
    themeName === "kumo"
      ? `:root[data-mode="dark"], [data-mode="dark"]:not([data-theme]), [data-mode="dark"] ${themeSelector}, ${themeSelector}[data-mode="dark"], ${themeSelector} [data-mode="dark"]`
      : `[data-mode="dark"] ${themeSelector}, ${themeSelector}[data-mode="dark"], ${themeSelector} [data-mode="dark"]`;

  const ruleLines: string[] = [];
  ruleLines.push(`${lightSelector} {`);

  for (const entry of textEntries) {
    ruleLines.push(`  --text-color-${entry.name}: ${entry.light};`);
  }

  for (const entry of colorEntries) {
    ruleLines.push(`  --color-${entry.name}: ${entry.light};`);
  }

  ruleLines.push("}");
  ruleLines.push("");
  ruleLines.push(`${darkSelector} {`);

  for (const entry of textEntries) {
    ruleLines.push(`  --text-color-${entry.name}: ${entry.dark};`);
  }

  for (const entry of colorEntries) {
    ruleLines.push(`  --color-${entry.name}: ${entry.dark};`);
  }

  ruleLines.push("}");

  lines.push("");
  if (options.wrapInBaseLayer) {
    lines.push("@layer base {");
    for (const line of ruleLines) {
      lines.push(`  ${line}`);
    }
    lines.push("}");
    return;
  }

  lines.push(...ruleLines);
}

/**
 * Generate the base kumo theme CSS
 * This contains all tokens with their kumo theme values
 */
export function generateKumoThemeCSS(
  config: ThemeConfig,
  useNewNames = false,
): string {
  const lines: string[] = [GENERATED_FILE_HEADER];

  // Text color tokens
  lines.push("@theme {");

  for (const [tokenName, def] of Object.entries(config.text)) {
    const name = useNewNames ? def.newName : tokenName;
    const kumoColors = def.theme.kumo;

    lines.push(
      `  --text-color-${name}: ${lightDark(kumoColors.light, kumoColors.dark)};`,
    );
    lines.push("");
  }

  lines.push("}");
  lines.push("");

  // Color tokens (bg, border, ring, etc.)
  lines.push("@theme {");

  for (const [tokenName, def] of Object.entries(config.color)) {
    const name = useNewNames ? def.newName : tokenName;
    const kumoColors = def.theme.kumo;

    lines.push(
      `  --color-${name}: ${lightDark(kumoColors.light, kumoColors.dark)};`,
    );
    lines.push("");
  }

  lines.push("}");

  // Typography tokens (font sizes and line heights)
  if (config.typography && Object.keys(config.typography).length > 0) {
    lines.push("");
    lines.push("@theme {");
    lines.push("  /* Typography - text sizes and line heights */");

    for (const [tokenName, def] of Object.entries(config.typography)) {
      const name = useNewNames && def.newName ? def.newName : tokenName;
      const value = def.theme.kumo;

      lines.push(`  --text-${name}: ${value};`);
    }

    lines.push("}");
  }

  // Explicit runtime vars avoid transient unresolved light-dark() values
  // during class/DOM mutations in some browser style recalculation paths.
  pushModeScopedBaseVariables(lines, config, "kumo", useNewNames, {
    wrapInBaseLayer: true,
  });

  return lines.join("\n");
}

/**
 * Generate a theme override CSS file
 * Only includes tokens that differ from the base kumo theme
 */
export function generateThemeOverrideCSS(
  config: ThemeConfig,
  themeName: string,
  useNewNames = false,
): string {
  if (themeName === "kumo") {
    throw new Error("Use generateKumoThemeCSS for the base kumo theme");
  }

  const overrides: string[] = [];

  // Collect text token overrides
  for (const [tokenName, def] of Object.entries(config.text)) {
    const themeColors = def.theme[themeName];
    if (themeColors) {
      const name = useNewNames ? def.newName : tokenName;
      overrides.push(
        `    --text-color-${name}: ${lightDark(themeColors.light, themeColors.dark)};`,
      );
    }
  }

  // Collect color token overrides
  for (const [tokenName, def] of Object.entries(config.color)) {
    const themeColors = def.theme[themeName];
    if (themeColors) {
      const name = useNewNames ? def.newName : tokenName;
      overrides.push(
        `    --color-${name}: ${lightDark(themeColors.light, themeColors.dark)};`,
      );
    }
  }

  // Collect typography token overrides
  if (config.typography) {
    for (const [tokenName, def] of Object.entries(config.typography)) {
      const themeValue = def.theme[themeName];
      if (themeValue) {
        const name = useNewNames && def.newName ? def.newName : tokenName;
        overrides.push(`    --text-${name}: ${themeValue};`);
      }
    }
  }

  if (overrides.length === 0) {
    return `${GENERATED_FILE_HEADER}/* No overrides for ${themeName} theme */\n`;
  }

  const lines = [
    GENERATED_FILE_HEADER,
    "@layer base {",
    `  [data-theme="${themeName}"] {`,
    ...overrides,
    "  }",
    "}",
  ];

  pushModeScopedBaseVariables(lines, config, themeName, useNewNames, {
    wrapInBaseLayer: true,
  });

  return `${lines.join("\n")}\n`;
}

/**
 * Get a mapping of old token names to new names
 * Useful for running codemods during migration
 */
export function getTokenRenameMap(config: ThemeConfig): TokenRenameMap {
  const textMap: Record<string, string> = {};
  const colorMap: Record<string, string> = {};

  for (const [tokenName, def] of Object.entries(config.text)) {
    textMap[tokenName] = def.newName;
  }

  for (const [tokenName, def] of Object.entries(config.color)) {
    colorMap[tokenName] = def.newName;
  }

  return { text: textMap, color: colorMap };
}

/**
 * Generate all theme CSS files
 */
export function generateAllThemes(
  options: GeneratorOptions,
): Map<string, string> {
  const { useNewNames = false, themes = [...AVAILABLE_THEMES] } = options;
  const files = new Map<string, string>();

  // Always generate base kumo theme
  if (themes.includes("kumo")) {
    files.set(
      "theme-kumo.css",
      generateKumoThemeCSS(THEME_CONFIG, useNewNames),
    );
  }

  // Generate override themes
  for (const themeName of themes) {
    if (themeName !== "kumo") {
      files.set(
        `theme-${themeName}.css`,
        generateThemeOverrideCSS(THEME_CONFIG, themeName, useNewNames),
      );
    }
  }

  return files;
}

/**
 * List all tokens with their current and new names
 * Useful for documentation and migration planning
 */
export function listAllTokens(config: ThemeConfig): Array<{
  type: "text" | "color" | "typography";
  currentName: string;
  newName: string;
  themes: string[];
}> {
  const tokens: Array<{
    type: "text" | "color" | "typography";
    currentName: string;
    newName: string;
    themes: string[];
  }> = [];

  for (const [tokenName, def] of Object.entries(config.text)) {
    tokens.push({
      type: "text",
      currentName: tokenName,
      newName: def.newName,
      themes: Object.keys(def.theme),
    });
  }

  for (const [tokenName, def] of Object.entries(config.color)) {
    tokens.push({
      type: "color",
      currentName: tokenName,
      newName: def.newName,
      themes: Object.keys(def.theme),
    });
  }

  if (config.typography) {
    for (const [tokenName, def] of Object.entries(config.typography)) {
      tokens.push({
        type: "typography",
        currentName: tokenName,
        newName: def.newName,
        themes: Object.keys(def.theme),
      });
    }
  }

  return tokens;
}
