/**
 * External dependencies
 */
// eslint-disable-next-line no-restricted-imports
import type * as React from 'react';

/**
 * Based on https://github.com/reakit/reakit/blob/master/packages/reakit-utils/src/types.ts
 *
 * The `children` prop is being explicitely omitted since it is otherwise implicitly added
 * by `ComponentPropsWithRef`. The context is that components should require the `children`
 * prop explicitely when needed (see https://github.com/GeChiUI/gutenberg/pull/31817).
 */
export type GeChiUIComponentProps<
	P,
	T extends React.ElementType,
	IsPolymorphic extends boolean = true
> = P &
	Omit< React.ComponentPropsWithRef< T >, 'as' | keyof P | 'children' > &
	( IsPolymorphic extends true
		? {
				as?: T | keyof JSX.IntrinsicElements;
		  }
		: { as?: never } );

export type GeChiUIComponent<
	T extends React.ElementType,
	O,
	IsPolymorphic extends boolean
> = {
	< TT extends React.ElementType >(
		props: GeChiUIComponentProps< O, TT, IsPolymorphic > &
			( IsPolymorphic extends true ? { as: TT } : { as: never } )
	): JSX.Element | null;
	(
		props: GeChiUIComponentProps< O, T, IsPolymorphic >
	): JSX.Element | null;
	displayName?: string;
	/**
	 * A CSS selector used to fake component interpolation in styled components
	 * for components not generated by `styled`. Anything passed to `contextConnect`
	 * will get this property.
	 *
	 * We restrict it to a class to align with the already existing class names that
	 * are generated by the context system.
	 */
	selector: `.${ string }`;
};

export type GeChiUIComponentFromProps<
	Props
> = Props extends GeChiUIComponentProps< infer P, infer T, infer I >
	? GeChiUIComponent< T, P, I >
	: never;
