'use client'

import type { ReactElement } from 'react'
import { useRender, type HTMLProps } from '@base-ui/react/use-render'
import { objectFromEntries } from 'ts-extras'

export type RenderFnProps = HTMLProps
export type RenderFnState = Record<string, unknown> | undefined

export type RenderFn<State extends RenderFnState = undefined, ElementProps = unknown> = (
  renderProps: RenderFnProps,
  state: State,
) => ReactElement<ElementProps>

/**
 * Type for a `render` prop that accepts either a React element or a render function.
 *
 * - **Element form**: Pass a React element to replace the default tag (e.g., `<strong />`).
 * - **Function form**: Pass a callback `(props, state) => ReactElement` for full control.
 *
 * @template State - The state object passed to the render function.
 * @template ElementProps - Optional constraint on the returned element's props (e.g., `{ disabled?:
 *   boolean }`).
 */
export type RenderProp<State extends RenderFnState = undefined, ElementProps = unknown> =
  | ReactElement<ElementProps>
  | RenderFn<State, ElementProps>

export interface RenderProps<State extends RenderFnState = undefined> {
  render: RenderProp<State>
  state?: State | undefined
  [key: string]: unknown
}

/**
 * A utility component that provides polymorphic rendering capabilities. It can render as any HTML
 * element or React component.
 */
export function Render<State extends RenderFnState>({
  render,
  state,
  ...props
}: RenderProps<State>) {
  return useRender({
    render,
    state: state !== undefined ? state : undefined,
    props,
    // Do not automatically add data attributes for state properties
    stateAttributesMapping: objectFromEntries(
      Object.keys(state ?? {}).map((stateProperty) => [stateProperty, () => null] as const),
    ),
  })
}
