/**
 * Theme system — design tokens that work SSR and client-side.
 *
 * Tokens are plain CSS custom properties (`--wire-<key>`) so they cascade and
 * can be overridden by user CSS. Each theme is a flat token map; the framework
 * ships default `light`/`dark` sets and the user's config deep-merges over them.
 *
 * The server renders `<html data-theme="…">` from the `wire-theme` cookie (no
 * flash), and a tiny client runtime toggles/persists it. The reserved token key
 * `color-scheme` is emitted as the native CSS property (not a variable) so form
 * controls and scrollbars match the theme.
 */

export type ThemeTokens = Record<string, string>;

export interface ThemeConfig {
  /** Name of the theme used when no `wire-theme` cookie is present. */
  default?: string;
  /** Named token maps. Deep-merged over the framework's built-in light/dark. */
  themes?: Record<string, ThemeTokens>;
}

export interface ResolvedTheme {
  default: string;
  names: string[];
  themes: Record<string, ThemeTokens>;
}

/** Cookie the resolved theme is read from / persisted to. */
export const THEME_COOKIE = "wire-theme";
export const THEME_CSS_HREF = "/__wrnexus/theme.css";
export const THEME_JS_HREF = "/__wrnexus/theme.js";

/** Built-in themes so components have tokens out of the box. */
export const DEFAULT_THEMES: Record<string, ThemeTokens> = {
  light: {
    "color-scheme": "light",
    "color-bg": "#ffffff",
    "color-surface": "#f6f7fb",
    "color-surface-2": "#eceff6",
    "color-text": "#0b1020",
    "color-muted": "#5a6178",
    "color-border": "#e2e6f0",
    "color-primary": "#2563eb",
    "color-primary-hover": "#1d4ed8",
    "color-primary-contrast": "#ffffff",
    "color-danger": "#dc2626",
    "color-success": "#16a34a",
    "color-warning": "#d97706",
    radius: "8px",
    "radius-sm": "5px",
    "font-sans": "system-ui, -apple-system, Segoe UI, Roboto, sans-serif",
    "shadow-1": "0 1px 2px rgba(16,24,40,0.06), 0 1px 3px rgba(16,24,40,0.1)",
  },
  dark: {
    "color-scheme": "dark",
    "color-bg": "#0b1020",
    "color-surface": "#141a30",
    "color-surface-2": "#1c243f",
    "color-text": "#e7ecff",
    "color-muted": "#9aa6d0",
    "color-border": "#ffffff1f",
    "color-primary": "#6c8cff",
    "color-primary-hover": "#8aa2ff",
    "color-primary-contrast": "#0b1020",
    "color-danger": "#f87171",
    "color-success": "#4ade80",
    "color-warning": "#fbbf24",
    radius: "10px",
    "radius-sm": "6px",
    "font-sans": "system-ui, -apple-system, Segoe UI, Roboto, sans-serif",
    "shadow-1": "0 1px 2px rgba(0,0,0,0.3), 0 4px 16px rgba(0,0,0,0.35)",
  },
};

/** Merge the user's theme config over the built-in defaults. */
export function resolveThemeConfig(config?: ThemeConfig): ResolvedTheme {
  const themes: Record<string, ThemeTokens> = {};
  const names = new Set<string>([
    ...Object.keys(DEFAULT_THEMES),
    ...Object.keys(config?.themes ?? {}),
  ]);
  for (const name of names) {
    themes[name] = { ...(DEFAULT_THEMES[name] ?? {}), ...(config?.themes?.[name] ?? {}) };
  }
  const list = Object.keys(themes);
  const preferred = config?.default && themes[config.default] ? config.default : undefined;
  const fallback = themes.dark ? "dark" : list[0]!;
  return { default: preferred ?? fallback, names: list, themes };
}

/** Pick a valid theme name from a cookie value, falling back to the default. */
export function resolveThemeName(cookieValue: string | undefined, theme: ResolvedTheme): string {
  return cookieValue && theme.themes[cookieValue] ? cookieValue : theme.default;
}

function tokensToDeclarations(tokens: ThemeTokens): string {
  return Object.entries(tokens)
    .map(([key, value]) =>
      key === "color-scheme" ? `color-scheme:${value};` : `--wire-${key}:${value};`,
    )
    .join("");
}

/** Generate the theme stylesheet: a `:root` default plus one block per theme. */
export function renderThemeCss(theme: ResolvedTheme): string {
  const blocks: string[] = [];
  const def = theme.themes[theme.default];
  if (def) blocks.push(`:root{${tokensToDeclarations(def)}}`);
  for (const name of theme.names) {
    blocks.push(`[data-theme="${name}"]{${tokensToDeclarations(theme.themes[name]!)}}`);
  }
  return blocks.join("\n") + "\n";
}

/**
 * Generate the client theme runtime. It exposes `window.wireTheme` and binds
 * `[data-wire-theme-toggle]` / `[data-wire-theme-set]` elements. The configured
 * theme names are baked in so `toggle()` cycles through them in order.
 */
export function renderThemeRuntime(theme: ResolvedTheme): string {
  const names = JSON.stringify(theme.names);
  return `(function(){
  var COOKIE=${JSON.stringify(THEME_COOKIE)};
  var THEMES=${names};
  var el=document.documentElement;
  function get(){return el.getAttribute("data-theme")||${JSON.stringify(theme.default)};}
  function set(name){
    if(THEMES.indexOf(name)<0)return;
    el.setAttribute("data-theme",name);
    document.cookie=COOKIE+"="+encodeURIComponent(name)+";path=/;max-age=31536000;samesite=lax";
  }
  function toggle(){var i=THEMES.indexOf(get());set(THEMES[(i+1)%THEMES.length]);}
  function bind(root){
    (root||document).querySelectorAll("[data-wire-theme-toggle]").forEach(function(n){
      if(n.__wireThemeBound)return;n.__wireThemeBound=1;
      n.addEventListener("click",function(){toggle();});
    });
    (root||document).querySelectorAll("[data-wire-theme-set]").forEach(function(n){
      if(n.__wireThemeBound)return;n.__wireThemeBound=1;
      n.addEventListener("click",function(){set(n.getAttribute("data-wire-theme-set"));});
    });
  }
  window.wireTheme={get:get,set:set,toggle:toggle,bind:bind,themes:THEMES};
  window.addEventListener("wrnexus:navigated",function(){bind(document);});
  if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",function(){bind(document);});
  else bind(document);
})();
`;
}
