// theme() — app theme variables (docs/ui-theme-plan.md). One global var table lives in the UI
// core; `var(--key)` references resolve at style-apply time, so re-calling theme() re-styles the
// LIVE UI. Bare style tokens (`pt: "comfort-top"`) are keywords that may expand to formulas
// (max(safe-top, knob)); `var(--comfort-top)` always reads the raw table value.

import type { Transition } from "./presentable"

export type ThemeValues = Record<string, string | number | null>

/** @internal Navigation defaults the theme owns; the router reads them at call time.
 *  (SDK-side state, deliberately NOT in the host var table — `var(--replaceTransition)`
 *  is not a style value.) */
export const _navDefaults: { replace: Transition } = { replace: "none" }

// (Unconstrained: it also maps inputs whose `replaceTransition` key was carved out.)
export type ThemeAccessors<T> = {
  readonly [K in keyof T]: K extends string ? `var(--${K})` : never
}

const RESERVED = ["safe-top", "safe-bottom", "safe-left", "safe-right", "vw", "vh", "vmin", "vmax"]

/**
 * Merge app theme variables into the live table and get typed `var(--key)` accessors back:
 *
 * ```ts
 * export const T = theme({ primaryColor: "#0A84FF", cardBg: "#1C1C1E" })
 * card.style({ bgColor: T.cardBg })   // T.cardBg === "var(--cardBg)"
 * ```
 *
 * Strings pass through (colors, fonts, expressions like `"max(safe-top, 24px)"`); numbers are
 * lengths (px); `null` removes a key (comfort knobs reset to their defaults). Env names
 * (`safe-*`, `vw`/`vh`/…) are host-owned — skipped with a warning. One special key:
 * `replaceTransition` — the app-wide default transition for `Router.replace` (consumed SDK-side,
 * never sent to the host table).
 */
const setTheme = <T extends Record<string, string | number | Transition | null>>(
  // Only `replaceTransition` may carry a Transition — every other key is a style value.
  values: T & { [K in Exclude<keyof T, "replaceTransition">]: string | number | null }
): ThemeAccessors<Omit<T, "replaceTransition">> => {
  const accessors: Record<string, string> = {}
  let send = values as ThemeValues
  const strip = (key: string) => {
    if (send === values) send = { ...values } as ThemeValues
    delete send[key]
  }
  for (const key of Object.keys(values)) {
    if (key === "replaceTransition") {
      _navDefaults.replace = (values[key] ?? "none") as Transition
      strip(key)   // SDK-consumed, no accessor: it isn't a style var
      continue
    }
    if (RESERVED.includes(key)) {
      console.warn(`theme(): "${key}" is an environment value (host-owned) — ignored`)
      strip(key)
      continue
    }
    accessors[key] = `var(--${key})`
  }
  // Optional during rollout: hosts without the method simply don't theme (values still type).
  if (Object.keys(send).length > 0) _creatorUI.setTheme?.(send)
  return accessors as ThemeAccessors<Omit<T, "replaceTransition">>
}

/** App theme: callable to merge variables (`theme({...})` — re-calling re-styles the live UI, so
 *  dark mode is just a second call), with the system vars as static properties
 *  (`theme.primaryColor`, `theme["comfort-top"]`, …). */
export const theme = Object.assign(setTheme, {
  /** The app accent color. Kit components will read it via `var(--primaryColor, <fallback>)`. */
  primaryColor: "var(--primaryColor)",
  /** Secondary / inactive content color for kit components. */
  mutedColor: "var(--mutedColor)",
  /** DEFAULT text color — text without an explicit `color` follows it (hosts source their
   *  default from the theme; unset = the host default, white on dark screens). Set it once for
   *  a light theme instead of `color: "black"` on every label. */
  color: "var(--color)",
  /** DEFAULT text font — text without an explicit `fontFamily` follows it. */
  fontFamily: "var(--fontFamily)",
  /** Raw comfort knobs (logical px). The bare `comfort-top` style TOKEN applies the safe-area
   *  formula — these accessors read the knob value itself, for manual composition. */
  "comfort-top": "var(--comfort-top)",
  "comfort-bottom": "var(--comfort-bottom)",
  "comfort-left": "var(--comfort-left)",
  "comfort-right": "var(--comfort-right)",
} as const)
