/* eslint-disable @typescript-eslint/no-explicit-any */
declare module 'netlify-cms-core' {
  import React, { ComponentType } from 'react';
  import { List, Map } from 'immutable';

  export type CmsBackendType = 'git-gateway' | 'github' | 'gitlab' | 'bitbucket' | 'test-repo';

  export type CmsMapWidgetType = 'Point' | 'LineString' | 'Polygon';

  export type CmsMarkdownWidgetButton =
    | 'bold'
    | 'italic'
    | 'code'
    | 'link'
    | 'heading-one'
    | 'heading-two'
    | 'heading-three'
    | 'heading-four'
    | 'heading-five'
    | 'heading-six'
    | 'quote'
    | 'code-block'
    | 'bulleted-list'
    | 'numbered-list';

  export interface CmsSelectWidgetOptionObject {
    label: string;
    value: any;
  }

  export type CmsCollectionFormatType =
    | 'yml'
    | 'yaml'
    | 'toml'
    | 'json'
    | 'frontmatter'
    | 'yaml-frontmatter'
    | 'toml-frontmatter'
    | 'json-frontmatter';

  export type CmsAuthScope = 'repo' | 'public_repo';

  export type CmsPublishMode = 'simple' | 'editorial_workflow';

  export type CmsSlugEncoding = 'unicode' | 'ascii';

  export interface CmsField {
    name: string;
    label?: string;
    widget?: string;
    required?: boolean;
    hint?: string;
    pattern?: [string, string];
    default?: any;

    /** If widget === "code" */
    default_language?: string;
    allow_language_selection?: boolean;
    keys?: { code: string; lang: string };
    output_code_only?: boolean;

    /** If widget === "datetime" */
    format?: string;
    date_format?: boolean | string;
    time_format?: boolean | string;
    picker_utc?: boolean;

    /**
     * @deprecated Use date_format instead
     */
    dateFormat?: boolean | string;
    /**
     * @deprecated Use time_format instead
     */
    timeFormat?: boolean | string;
    /**
     * @deprecated Use picker_utc instead
     */
    pickerUtc?: boolean;

    /** If widget === "file" || widget === "image" */
    media_library?: CmsMediaLibrary;
    allow_multiple?: boolean;
    config?: any;

    /** If widget === "object" || widget === "list" */
    fields?: CmsField[];
    collapsed?: boolean;

    /** If widget === "list" */
    field?: CmsField;
    allow_add?: boolean;
    summary?: string;
    minimize_collapsed?: boolean;
    label_singular?: string;
    types?: CmsField[];

    /** If widget === "map" */
    decimals?: number;
    type?: CmsMapWidgetType;

    /** If widget === "markdown" */
    minimal?: boolean;
    buttons?: CmsMarkdownWidgetButton[];
    editor_components?: string[];

    /**
     * @deprecated Use editor_components instead
     */
    editorComponents?: string[];

    /** If widget === "number" */
    value_type?: 'int' | 'float' | string;
    step?: number;

    /**
     * @deprecated Use valueType instead
     */
    valueType?: 'int' | 'float' | string;

    /** If widget === "number" || widget === "select" */
    min?: number;
    max?: number;

    /** If widget === "relation" || widget === "select" */
    multiple?: boolean;

    /** If widget === "relation" */
    collection?: string;
    value_field?: string;
    search_fields?: string[];
    file?: string;
    display_fields?: string[];
    options_length?: number;

    /**
     * @deprecated Use value_field instead
     */
    valueField?: string;
    /**
     * @deprecated Use search_fields instead
     */
    searchFields?: string[];
    /**
     * @deprecated Use display_fields instead
     */
    displayFields?: string[];
    /**
     * @deprecated Use options_length instead
     */
    optionsLength?: number;

    /** If widget === "select" */
    options?: string[] | CmsSelectWidgetOptionObject[];
  }

  export interface CmsCollectionFile {
    name: string;
    label: string;
    file: string;
    fields: CmsField[];
    label_singular?: string;
    description?: string;
  }

  export interface CmsCollection {
    name: string;
    label: string;
    label_singular?: string;
    description?: string;
    folder?: string;
    files?: CmsCollectionFile[];
    identifier_field?: string;
    summary?: string;
    slug?: string;
    preview_path?: string;
    preview_path_date_field?: string;
    create?: boolean;
    delete?: boolean;
    editor?: {
      preview?: boolean;
    };

    /**
     * It accepts the following values: yml, yaml, toml, json, md, markdown, html
     *
     * You may also specify a custom extension not included in the list above, by specifying the format value.
     */
    extension?: string;
    format?: CmsCollectionFormatType;

    frontmatter_delimiter?: string[] | string;
    fields?: CmsField[];
    filter?: { field: string; value: any };
    path?: string;
    media_folder?: string;
    public_folder?: string;
    sortable_fields?: string[];

    /**
     * @deprecated Use sortable_fields instead
     */
    sortableFields?: string[];
  }

  export interface CmsBackend {
    name: CmsBackendType;
    auth_scope?: CmsAuthScope;
    open_authoring?: boolean;
    repo?: string;
    branch?: string;
    api_root?: string;
    site_domain?: string;
    base_url?: string;
    auth_endpoint?: string;
    cms_label_prefix?: string;
  }

  export interface CmsSlug {
    encoding?: CmsSlugEncoding;
    clean_accents?: boolean;
  }

  export interface CmsConfig {
    backend: CmsBackend;
    collections: CmsCollection[];
    locale?: string;
    site_url?: string;
    display_url?: string;
    logo_url?: string;
    show_preview_links?: boolean;
    media_folder?: string;
    public_folder?: string;
    media_folder_relative?: boolean;
    media_library?: CmsMediaLibrary;
    publish_mode?: CmsPublishMode;
    slug?: CmsSlug;
  }

  export interface InitOptions {
    config: CmsConfig;
  }

  export interface EditorComponentField {
    name: string;
    label: string;
    widget: string;
  }

  export interface EditorComponentOptions {
    id: string;
    label: string;
    fields: EditorComponentField[];
    pattern: RegExp;
    allow_add?: boolean;
    fromBlock: (match: RegExpMatchArray) => any;
    toBlock: (data: any) => string;
    toPreview: (data: any) => string;
  }

  export interface PreviewStyleOptions {
    raw: boolean;
  }

  export interface PreviewStyle extends PreviewStyleOptions {
    value: string;
  }

  export type CmsBackendClass = any; // TODO: type properly

  export interface CmsRegistryBackend {
    init: (args: any) => CmsBackendClass;
  }

  export interface CmsWidgetParam {
    name: string;
    controlComponent: ComponentType<any>;
    previewComponent?: ComponentType<any>;
    globalStyles: any;
  }

  export interface CmsWidget {
    control: ComponentType<any>;
    preview?: ComponentType<any>;
    globalStyles?: any;
  }

  export type CmsWidgetValueSerializer = any; // TODO: type properly

  export type CmsMediaLibraryOptions = any; // TODO: type properly

  export interface CmsMediaLibrary {
    name: string;
    config?: CmsMediaLibraryOptions;
  }

  export type CmsLocalePhrases = any; // TODO: type properly

  export interface CmsRegistry {
    backends: {
      [name: string]: CmsRegistryBackend;
    };
    templates: {
      [name: string]: ComponentType<any>;
    };
    previewStyles: PreviewStyle[];
    widgets: {
      [name: string]: CmsWidget;
    };
    editorComponents: Map<string, ComponentType<any>>;
    widgetValueSerializers: {
      [name: string]: CmsWidgetValueSerializer;
    };
    mediaLibraries: CmsMediaLibrary[];
    locales: {
      [name: string]: CmsLocalePhrases;
    };
  }

  type GetAssetFunction = (
    asset: string,
  ) => { url: string; path: string; field?: any; fileObj: File };

  export type PreviewTemplateComponentProps = {
    entry: Map<string, any>;
    collection: Map<string, any>;
    widgetFor: (name: any, fields?: any, values?: any, fieldsMetaData?: any) => JSX.Element | null;
    widgetsFor: (name: any) => any;
    getAsset: GetAssetFunction;
    boundGetAsset: (collection: any, path: any) => GetAssetFunction;
    fieldsMetaData: Map<string, any>;
    config: Map<string, any>;
    fields: List<Map<string, any>>;
    isLoadingAsset: boolean;
  };

  export interface CMS {
    getBackend: (name: string) => CmsRegistryBackend | undefined;
    getEditorComponents: () => Map<string, ComponentType<any>>;
    getLocale: (locale: string) => CmsLocalePhrases | undefined;
    getMediaLibrary: (name: string) => CmsMediaLibrary | undefined;
    getPreviewStyles: () => PreviewStyle[];
    getPreviewTemplate: (name: string) => ComponentType<PreviewTemplateComponentProps> | undefined;
    getWidget: (name: string) => CmsWidget | undefined;
    getWidgetValueSerializer: (widgetName: string) => CmsWidgetValueSerializer | undefined;
    init: (options?: InitOptions) => void;
    registerBackend: (name: string, backendClass: CmsBackendClass) => void;
    registerEditorComponent: (options: EditorComponentOptions) => void;
    registerLocale: (locale: string, phrases: CmsLocalePhrases) => void;
    registerMediaLibrary: (mediaLibrary: CmsMediaLibrary, options?: CmsMediaLibraryOptions) => void;
    registerPreviewStyle: (filePath: string, options?: PreviewStyleOptions) => void;
    registerPreviewTemplate: (
      name: string,
      component: ComponentType<PreviewTemplateComponentProps>,
    ) => void;
    registerWidget: (
      widget: string | CmsWidgetParam,
      control?: ComponentType<any>,
      preview?: ComponentType<any>,
    ) => void;
    registerWidgetValueSerializer: (
      widgetName: string,
      serializer: CmsWidgetValueSerializer,
    ) => void;
    resolveWidget: (name: string) => CmsWidget | undefined;
  }

  export const NetlifyCmsCore: CMS;

  export default NetlifyCmsCore;
}