/** runtime half of the in-house recipe. maps runtime options to precomputed class names. */

export type VariantValue = boolean | number | string;
type Selection = Record<string, VariantValue | undefined>;

/** Serialized recipe data produced at build time and embedded into the client bundle. */
export type RecipeConfig = {
	/** `[variantMatch, className]` pairs; a match value may be an array meaning "any of". */
	compoundVariants: [Record<string, VariantValue | VariantValue[]>, string][];
	/** Always-applied class(es), space-joined. */
	defaultClassName: string;
	defaultVariants: Selection;
	/** `variantName -> variantValue -> className`. Keys are stringified variant values. */
	variantClassNames: Record<string, Record<string, string>>;
};

export type RecipeFn = (props?: Selection) => string;

const matches = (expected: VariantValue | VariantValue[], actual: VariantValue | undefined): boolean => {
	if (Array.isArray(expected)) {
		return expected.some((value) => value === actual);
	}
	return expected === actual;
};

/**
 * Rebuilds a recipe's variant-selecting function from its serialized config.
 *
 * @param config build-time-extracted class names and variant metadata
 * @returns a function mapping a variant selection to the resolved class string
 */
export const createRuntimeFn = (config: RecipeConfig): RecipeFn => {
	return (props) => {
		const selections: Selection = { ...config.defaultVariants };
		if (props) {
			for (const name in props) {
				const value = props[name];
				if (value !== undefined) {
					selections[name] = value;
				}
			}
		}
		let className = config.defaultClassName;

		for (const name in config.variantClassNames) {
			const selected = selections[name];
			if (selected == null) {
				continue;
			}
			const variantClass = config.variantClassNames[name]?.[String(selected)];
			if (variantClass) {
				className += ' ' + variantClass;
			}
		}

		for (const [check, compoundClass] of config.compoundVariants) {
			let applies = true;
			for (const name in check) {
				const expected = check[name];
				if (expected !== undefined && !matches(expected, selections[name])) {
					applies = false;
					break;
				}
			}
			if (applies) {
				className += ' ' + compoundClass;
			}
		}

		return className;
	};
};
