// Types for the WordPress script packages the plugin uses. WordPress provides
// these packages as globals at runtime (scripts/build.mjs maps the imports), so
// only the parts the plugin calls are declared here.

declare module '@wordpress/element' {
  import type { ReactElement, ReactNode } from 'react';

  export {
    Fragment,
    createContext,
    createElement,
    useCallback,
    useContext,
    useEffect,
    useId,
    useLayoutEffect,
    useMemo,
    useReducer,
    useRef,
    useState,
  } from 'react';
  export type { ComponentType, Dispatch, ReactElement, ReactNode, SetStateAction } from 'react';

  export interface Root {
    render(children: ReactNode): void;
    unmount(): void;
  }
  export function createRoot(container: Element): Root;
  export function createInterpolateElement(
    interpolatedString: string,
    conversionMap: Record<string, ReactElement>,
  ): ReactElement;
}

declare module '@wordpress/i18n' {
  export function __(text: string, domain?: string): string;
  export function _x(text: string, context: string, domain?: string): string;
  export function _n(single: string, plural: string, number: number, domain?: string): string;
  export function sprintf(format: string, ...args: Array<string | number>): string;
  export function isRTL(): boolean;
}

declare module '@wordpress/api-fetch' {
  export interface APIFetchOptions {
    path?: string;
    url?: string;
    method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
    data?: unknown;
    parse?: boolean;
    headers?: Record<string, string>;
    signal?: AbortSignal;
  }
  export default function apiFetch<T = unknown>(options: APIFetchOptions): Promise<T>;
}

declare module '@wordpress/url' {
  export function addQueryArgs(url: string, args: Record<string, string | number | boolean | undefined>): string;
}

declare module '@wordpress/dom-ready' {
  export default function domReady(callback: () => void): void;
}

declare module '@wordpress/components' {
  import type {
    ChangeEvent,
    ComponentType,
    CSSProperties,
    FormEvent,
    KeyboardEvent,
    MouseEvent,
    ReactElement,
    ReactNode,
    Ref,
  } from 'react';

  type Children = { children?: ReactNode };

  export interface ButtonProps extends Children {
    variant?: 'primary' | 'secondary' | 'tertiary' | 'link';
    isDestructive?: boolean;
    isBusy?: boolean;
    isPressed?: boolean;
    disabled?: boolean;
    accessibleWhenDisabled?: boolean;
    href?: string;
    target?: string;
    rel?: string;
    type?: 'button' | 'submit' | 'reset';
    icon?: ReactElement | string;
    iconPosition?: 'left' | 'right';
    label?: string;
    showTooltip?: boolean;
    size?: 'default' | 'compact' | 'small';
    text?: string;
    id?: string;
    className?: string;
    style?: CSSProperties;
    onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
    __next40pxDefaultSize?: boolean;
    'aria-label'?: string;
    'aria-pressed'?: boolean;
    'aria-expanded'?: boolean;
    'aria-controls'?: string;
    'aria-describedby'?: string;
    'data-testid'?: string;
  }
  export const Button: ComponentType<ButtonProps>;

  interface CardPartProps extends Children {
    className?: string;
    size?: 'xSmall' | 'small' | 'medium' | 'large';
    isBorderless?: boolean;
    isShady?: boolean;
    id?: string;
  }
  export const Card: ComponentType<CardPartProps>;
  export const CardHeader: ComponentType<CardPartProps>;
  export const CardBody: ComponentType<CardPartProps>;
  export const CardFooter: ComponentType<CardPartProps>;
  export const CardDivider: ComponentType<{ className?: string }>;

  interface FlexProps extends Children {
    className?: string;
    direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse';
    justify?: CSSProperties['justifyContent'];
    align?: CSSProperties['alignItems'];
    gap?: number;
    wrap?: boolean;
    expanded?: boolean;
    style?: CSSProperties;
  }
  export const Flex: ComponentType<FlexProps>;
  export const FlexItem: ComponentType<Children & { className?: string; style?: CSSProperties }>;
  export const FlexBlock: ComponentType<Children & { className?: string; style?: CSSProperties }>;

  export interface NoticeAction {
    label: string;
    onClick?: () => void;
    url?: string;
    variant?: 'primary' | 'secondary' | 'link';
    className?: string;
  }
  export const Notice: ComponentType<
    Children & {
      status?: 'success' | 'info' | 'warning' | 'error';
      isDismissible?: boolean;
      onRemove?: () => void;
      actions?: NoticeAction[];
      className?: string;
      politeness?: 'polite' | 'assertive';
    }
  >;

  export const Spinner: ComponentType<{ className?: string }>;

  interface ControlBase {
    label?: ReactNode;
    help?: ReactNode;
    hideLabelFromVision?: boolean;
    disabled?: boolean;
    className?: string;
    id?: string;
    __nextHasNoMarginBottom?: boolean;
    __next40pxDefaultSize?: boolean;
  }

  export const ToggleControl: ComponentType<
    ControlBase & {
      checked: boolean;
      onChange: (checked: boolean) => void;
    }
  >;

  export const TextControl: ComponentType<
    ControlBase & {
      value: string | number;
      onChange: (value: string) => void;
      type?: 'text' | 'email' | 'url' | 'number' | 'search' | 'tel' | 'password';
      placeholder?: string;
      autoComplete?: string;
      readOnly?: boolean;
      min?: number;
      max?: number;
      step?: number;
      maxLength?: number;
      onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
      onBlur?: () => void;
      'aria-describedby'?: string;
    }
  >;

  export const TextareaControl: ComponentType<
    ControlBase & {
      value: string;
      onChange: (value: string) => void;
      rows?: number;
      placeholder?: string;
      readOnly?: boolean;
      maxLength?: number;
    }
  >;

  export interface SelectOption {
    label: string;
    value: string;
    disabled?: boolean;
  }
  export const SelectControl: ComponentType<
    ControlBase & {
      value?: string;
      options: SelectOption[];
      onChange: (value: string) => void;
    }
  >;

  export const CheckboxControl: ComponentType<
    ControlBase & {
      checked: boolean;
      onChange: (checked: boolean) => void;
      indeterminate?: boolean;
    }
  >;

  export const RadioControl: ComponentType<
    ControlBase & {
      selected?: string;
      options: Array<{ label: string; value: string }>;
      onChange: (value: string) => void;
    }
  >;

  export const RangeControl: ComponentType<
    ControlBase & {
      value?: number;
      onChange: (value?: number) => void;
      min?: number;
      max?: number;
      step?: number;
      allowReset?: boolean;
      withInputField?: boolean;
    }
  >;

  export const SearchControl: ComponentType<{
    value: string;
    onChange: (value: string) => void;
    label?: string;
    placeholder?: string;
    className?: string;
    __nextHasNoMarginBottom?: boolean;
    __next40pxDefaultSize?: boolean;
  }>;

  export interface ComboboxOption {
    label: string;
    value: string;
  }
  export const ComboboxControl: ComponentType<
    ControlBase & {
      value: string | null;
      options: ComboboxOption[];
      onChange: (value?: string | null) => void;
      onFilterValueChange?: (value: string) => void;
      allowReset?: boolean;
    }
  >;

  export interface TabPanelTab {
    name: string;
    title: string;
    className?: string;
    disabled?: boolean;
  }
  export const TabPanel: ComponentType<{
    tabs: TabPanelTab[];
    children: (tab: TabPanelTab) => ReactNode;
    initialTabName?: string;
    onSelect?: (tabName: string) => void;
    className?: string;
    activeClass?: string;
    orientation?: 'horizontal' | 'vertical';
  }>;

  export const Modal: ComponentType<
    Children & {
      title: string;
      onRequestClose: () => void;
      size?: 'small' | 'medium' | 'large' | 'fill';
      className?: string;
      shouldCloseOnClickOutside?: boolean;
      isDismissible?: boolean;
      focusOnMount?: boolean | 'firstElement' | 'firstContentElement';
    }
  >;

  export const ExternalLink: ComponentType<Children & { href: string; className?: string }>;

  interface BaseControlComponent extends ComponentType<ControlBase & Children> {
    VisualLabel: ComponentType<Children & { as?: string }>;
  }
  export const BaseControl: BaseControlComponent;

  export const Panel: ComponentType<Children & { header?: string; className?: string }>;
  export const PanelBody: ComponentType<
    Children & {
      title?: string;
      initialOpen?: boolean;
      opened?: boolean;
      onToggle?: (next: boolean) => void;
      className?: string;
    }
  >;
  export const PanelRow: ComponentType<Children & { className?: string }>;

  export interface PaletteColor {
    name: string;
    slug?: string;
    color: string;
  }
  export const ColorPalette: ComponentType<{
    colors?: PaletteColor[];
    value?: string;
    onChange: (color?: string) => void;
    clearable?: boolean;
    disableCustomColors?: boolean;
    enableAlpha?: boolean;
    className?: string;
  }>;

  export const Placeholder: ComponentType<
    Children & { label?: string; icon?: ReactElement | string; instructions?: string; className?: string }
  >;

  export const VisuallyHidden: ComponentType<Children & { as?: string }>;
  export const Tooltip: ComponentType<{ text: string; children: ReactElement }>;
  export const Dashicon: ComponentType<{ icon: string; className?: string }>;
  export const ToolbarGroup: ComponentType<Children>;
  export const ToolbarButton: ComponentType<{
    icon?: ReactElement | string;
    label: string;
    onClick?: () => void;
    isPressed?: boolean;
  }>;

  export const Disabled: ComponentType<Children & { isDisabled?: boolean }>;

  export type InputChangeEvent = ChangeEvent<HTMLInputElement>;
  export type FormSubmitEvent = FormEvent<HTMLFormElement>;
  export type ForwardRef<T> = Ref<T>;
}

declare module '@wordpress/blocks' {
  import type { ComponentType, ReactNode } from 'react';

  export interface BlockEditProps<A> {
    attributes: A;
    setAttributes: (attributes: Partial<A>) => void;
    clientId: string;
    isSelected: boolean;
    context: Record<string, unknown>;
  }

  export interface BlockSettings<A> {
    edit: ComponentType<BlockEditProps<A>>;
    save?: () => ReactNode;
    icon?: ReactNode;
    [key: string]: unknown;
  }

  export interface BlockMetadata {
    name: string;
    [key: string]: unknown;
  }

  export function registerBlockType<A>(metadata: BlockMetadata | string, settings: BlockSettings<A>): unknown;
  export function getBlockType(name: string): unknown;
}

declare module '@wordpress/block-editor' {
  import type { ComponentType, CSSProperties, ReactNode } from 'react';

  interface BlockProps {
    className?: string;
    style?: CSSProperties;
    [key: string]: unknown;
  }

  interface UseBlockProps {
    (props?: BlockProps): BlockProps;
    save(props?: BlockProps): BlockProps;
  }
  export const useBlockProps: UseBlockProps;

  interface InnerBlocksComponent
    extends ComponentType<{
      allowedBlocks?: string[];
      template?: Array<[string, Record<string, unknown>?]>;
      templateLock?: false | 'all' | 'insert' | 'contentOnly';
      renderAppender?: false | ComponentType;
    }> {
    Content: ComponentType;
    ButtonBlockAppender: ComponentType;
  }
  export const InnerBlocks: InnerBlocksComponent;

  export function useInnerBlocksProps(
    props?: BlockProps,
    options?: {
      allowedBlocks?: string[];
      template?: Array<[string, Record<string, unknown>?]>;
      templateLock?: false | 'all' | 'insert' | 'contentOnly';
    },
  ): BlockProps & { children?: ReactNode };

  export const InspectorControls: ComponentType<{ children?: ReactNode; group?: 'settings' | 'advanced' | 'styles' | 'color' }>;
  export const BlockControls: ComponentType<{ children?: ReactNode; group?: 'default' | 'block' | 'other' }>;

  export const RichText: ComponentType<{
    tagName?: string;
    value: string;
    onChange: (value: string) => void;
    placeholder?: string;
    allowedFormats?: string[];
    withoutInteractiveFormatting?: boolean;
    className?: string;
    identifier?: string;
    'aria-label'?: string;
  }>;

  export interface MediaItem {
    id: number;
    url: string;
    alt?: string;
    mime?: string;
    type?: string;
  }
  export const MediaUpload: ComponentType<{
    onSelect: (media: MediaItem) => void;
    allowedTypes?: string[];
    value?: number;
    render: (props: { open: () => void }) => ReactNode;
  }>;
  export const MediaUploadCheck: ComponentType<{ children?: ReactNode }>;

  export function useSettings(...paths: string[]): unknown[];
}

declare module '@wordpress/data' {
  export function useSelect<T>(mapSelect: (select: (store: string | object) => any) => T, deps?: unknown[]): T;
  export function useDispatch(store: string | object): any;
  export function select(store: string | object): any;
  export function dispatch(store: string | object): any;
  export function subscribe(listener: () => void, store?: string | object): () => void;
}

declare module '@wordpress/editor' {
  import type { ComponentType, ReactNode } from 'react';

  export const PluginDocumentSettingPanel: ComponentType<{
    name: string;
    title: string;
    className?: string;
    icon?: ReactNode;
    children?: ReactNode;
  }>;
  export const store: object;
}

declare module '@wordpress/plugins' {
  import type { ComponentType, ReactNode } from 'react';

  export function registerPlugin(name: string, settings: { render: ComponentType; icon?: ReactNode }): unknown;
}
