"use client";

import { createContext, type ReactNode, useContext } from "react";

import type { FlagKey, FlagRegistry, FlagSnapshot } from "../define-flags";

/**
 * Creates typed React helpers for a flag registry.
 *
 * Call once with your registry type, then export the returned `FlagProvider`,
 * `Flag`, and `useFlag` from an application-local module.
 *
 * @example
 * ```tsx
 * export const { Flag, FlagProvider, useFlag } =
 *   createFlagContext<typeof flags>();
 * ```
 */
export function createFlagContext<TRegistry extends FlagRegistry>() {
  type Snapshot = FlagSnapshot<TRegistry>;

  const FlagContext = createContext<Snapshot | null>(null);

  /**
   * Provides a resolved flag snapshot to `Flag` and `useFlag`.
   *
   * @example
   * ```tsx
   * <FlagProvider flags={resolveAllFlags(flags)}>{children}</FlagProvider>
   * ```
   */
  function FlagProvider({
    children,
    flags,
  }: {
    readonly children: ReactNode;
    readonly flags: Snapshot;
  }) {
    return <FlagContext.Provider value={flags}>{children}</FlagContext.Provider>;
  }

  /**
   * Reads a typed flag value from the nearest `FlagProvider`.
   *
   * @example
   * ```tsx
   * const enabled = useFlag("NEW_CHECKOUT");
   * ```
   */
  function useFlag(flag: FlagKey<TRegistry>): boolean {
    const flags = useContext(FlagContext);
    return flags?.[flag] === true;
  }

  /**
   * Renders children when a typed flag is enabled, otherwise renders fallback.
   *
   * @example
   * ```tsx
   * <Flag flag="NEW_CHECKOUT" fallback={null}>Enabled content</Flag>
   * ```
   */
  function Flag({
    children,
    fallback = null,
    flag,
  }: {
    readonly children: ReactNode;
    readonly fallback?: ReactNode;
    readonly flag: FlagKey<TRegistry>;
  }) {
    return useFlag(flag) ? children : fallback;
  }

  return { Flag, FlagProvider, useFlag };
}
