/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict
 *
 * Utilities for flattening nested design token objects into dot-separated
 * flat keys, and unflattening them back. This is the core algorithm that
 * enables the unstable_defineVarsNested / unstable_defineConstsNested /
 * unstable_createThemeNested APIs.
 *
 * Architecture:
 *   Nested input → flattenImpl() → existing flat transforms → unflattenObject() → nested output
 *
 * A single generic flattenImpl<T> accepts isLeaf/transformLeaf callbacks,
 * enabling 4 flatten variants (vars, overrides, strings, consts) without
 * code duplication.
 */

import type { VarsConfigValue } from './stylex-vars-utils';
import { type CSSType } from './types';

// === Nested value types ===

// A nested vars value is a string, CSSType, or namespace containing more nested values.
// Conditional objects (with 'default' key) are structurally compatible with the namespace type.
export type NestedVarsValue =
  | string
  | CSSType<string | number>
  | $ReadOnly<{ +[string]: NestedVarsValue }>;

// A nested string value is either a string or a namespace of strings (for themeVars)
export type NestedStringValue =
  | string
  | $ReadOnly<{ +[string]: NestedStringValue }>;

// A nested consts value is either string/number or a namespace
export type NestedConstsValue =
  | string
  | number
  | $ReadOnly<{ +[string]: NestedConstsValue }>;

// === Public flatten functions ===
// Each is a thin wrapper around flattenImpl with a specific isLeaf/transformLeaf pair.
// Adding a new flatten variant requires only: 1 isLeaf function + 1 public wrapper.

/**
 * Flattens a nested token object for unstable_defineVarsNested.
 * Stops at strings, CSSType values, and conditional @-rule objects (with `default` key).
 *
 * Example:
 *   Input:  { button: { bg: 'red', color: { default: 'blue', '@media ...': 'dark' } } }
 *   Output: { 'button.bg': 'red', 'button.color': { default: 'blue', '@media ...': 'dark' } }
 */
declare export function flattenNestedVarsConfig(
  obj: $ReadOnly<{ +[string]: NestedVarsValue }>,
  prefix?: string,
): { [string]: VarsConfigValue | CSSType<string | number> };

/**
 * Flattens override values for unstable_createThemeNested.
 * Same leaf detection as vars, but CSSType values are unwrapped
 * (extracts .value) because createTheme expects plain VarsConfigValue.
 */
declare export function flattenNestedOverridesConfig(
  obj: $ReadOnly<{ +[string]: NestedVarsValue }>,
  prefix?: string,
): { [string]: VarsConfigValue };

/**
 * Flattens the compiled themeVars object (from defineVarsNested output)
 * which only contains var(--hash) strings at the leaves.
 * Used by createThemeNested to flatten the first argument.
 */
declare export function flattenNestedStringConfig(
  obj: $ReadOnly<{ +[string]: NestedStringValue }>,
  prefix?: string,
): { [string]: string };

/**
 * Flattens a nested token object for unstable_defineConstsNested.
 * Only strings and numbers are leaves — ALL objects are recursed into.
 * This means { default: '#00FF00', hovered: '#0000FF' } becomes two
 * separate flat keys, NOT a conditional value.
 *
 * Example:
 *   Input:  { button: { background: { default: '#00FF00', hovered: '#0000FF' } } }
 *   Output: { 'button.background.default': '#00FF00', 'button.background.hovered': '#0000FF' }
 */
declare export function flattenNestedConstsConfig(
  obj: $ReadOnly<{ +[string]: NestedConstsValue }>,
  prefix?: string,
): { [string]: string | number };

// === Unflatten ===

// Recursive unflattened value: either a leaf V or a nested object of more Unflattened<V>.
export type Unflattened<V> = V | { [string]: Unflattened<V> };

declare export function unflattenObject<V>(flatObj: { +[string]: V }): {
  [string]: Unflattened<V>,
};
