import type { ReactNode } from "react";
import type {
  Catalog,
  InferCatalogComponents,
  InferCatalogActions,
  InferComponentProps,
  InferActionParams,
} from "@json-render/core";

// =============================================================================
// State Types
// =============================================================================

/**
 * State setter function for updating application state
 */
export type SetState = (
  updater: (prev: Record<string, unknown>) => Record<string, unknown>,
) => void;

/**
 * State model type (generic record)
 */
export type StateModel = Record<string, unknown>;

// =============================================================================
// Component Types
// =============================================================================

/**
 * Context passed to component render functions
 * @example
 * const Button: ComponentFn<typeof catalog, 'Button'> = (ctx) => {
 *   return <button onClick={() => ctx.emit?.("press")}>{ctx.props.label}</button>
 * }
 */
export interface ComponentContext<
  C extends Catalog,
  K extends keyof InferCatalogComponents<C>,
> {
  props: InferComponentProps<C, K>;
  children?: ReactNode;
  /** Emit a named event. The renderer resolves the event to an action binding from the element's `on` field. */
  emit?: (event: string) => void;
  loading?: boolean;
}

/**
 * Component render function type for React
 * @example
 * const Button: ComponentFn<typeof catalog, 'Button'> = ({ props, emit }) => (
 *   <button onClick={() => emit?.("press")}>{props.label}</button>
 * );
 */
export type ComponentFn<
  C extends Catalog,
  K extends keyof InferCatalogComponents<C>,
> = (ctx: ComponentContext<C, K>) => ReactNode;

/**
 * Registry of all component render functions for a catalog
 * @example
 * const components: Components<typeof myCatalog> = {
 *   Button: ({ props }) => <button>{props.label}</button>,
 *   Input: ({ props }) => <input placeholder={props.placeholder} />,
 * };
 */
export type Components<C extends Catalog> = {
  [K in keyof InferCatalogComponents<C>]: ComponentFn<C, K>;
};

// =============================================================================
// Action Types
// =============================================================================

/**
 * Action handler function type
 * @example
 * const viewCustomers: ActionFn<typeof catalog, 'viewCustomers'> = async (params, setState) => {
 *   const data = await fetch('/api/customers');
 *   setState(prev => ({ ...prev, customers: data }));
 * };
 */
export type ActionFn<
  C extends Catalog,
  K extends keyof InferCatalogActions<C>,
> = (
  params: InferActionParams<C, K> | undefined,
  setState: SetState,
  state: StateModel,
) => Promise<void>;

/**
 * Registry of all action handlers for a catalog
 * @example
 * const actions: Actions<typeof myCatalog> = {
 *   viewCustomers: async (params, setState) => { ... },
 *   createCustomer: async (params, setState) => { ... },
 * };
 */
export type Actions<C extends Catalog> = {
  [K in keyof InferCatalogActions<C>]: ActionFn<C, K>;
};
