import type {ComponentType} from 'react'
import {CreateDataAttribute} from '@sanity/visual-editing-csm'
import {createDataAttribute} from '@sanity/visual-editing-csm'
import {CreateDataAttributeProps} from '@sanity/visual-editing-csm'
import {DocumentSchema} from '@sanity/presentation-comlink'
import type {FunctionComponent} from 'react'
import {HistoryRefresh} from '@sanity/presentation-comlink'
import {HistoryUpdate} from '@sanity/presentation-comlink'
import type {HTMLAttributes} from 'react'
import type {PropsWithChildren} from 'react'
import type {ReactElement} from 'react'
import {SanityNode} from '@sanity/presentation-comlink'
import {SchemaArrayItem} from '@sanity/presentation-comlink'
import {SchemaArrayNode} from '@sanity/presentation-comlink'
import {SchemaBooleanNode} from '@sanity/presentation-comlink'
import {SchemaInlineNode} from '@sanity/presentation-comlink'
import {SchemaNode} from '@sanity/presentation-comlink'
import {SchemaNullNode} from '@sanity/presentation-comlink'
import {SchemaNumberNode} from '@sanity/presentation-comlink'
import {SchemaObjectField} from '@sanity/presentation-comlink'
import {SchemaObjectNode} from '@sanity/presentation-comlink'
import {SchemaStringNode} from '@sanity/presentation-comlink'
import {SchemaUnionNode} from '@sanity/presentation-comlink'
import {SchemaUnionNodeOptions} from '@sanity/presentation-comlink'
import {SchemaUnionOption} from '@sanity/presentation-comlink'
import {SchemaUnknownNode} from '@sanity/presentation-comlink'
import {WithRequired} from '@sanity/visual-editing-csm'

export {CreateDataAttribute}

export {createDataAttribute}

export {CreateDataAttributeProps}

export {DocumentSchema}

/**
 * An element that is safe to parse
 * @internal
 */
export declare type ElementNode = HTMLElement | SVGElement

/**
 *
 * @public
 */
export declare interface HistoryAdapter {
  subscribe: (navigate: HistoryAdapterNavigate) => () => void
  update: (update: HistoryUpdate) => void
}

/**
 *
 * @public
 */
export declare type HistoryAdapterNavigate = (update: HistoryUpdate) => void

export {HistoryRefresh}

export {HistoryUpdate}

/**
 * @public
 */
export declare type OverlayComponent<
  T extends Record<string, unknown> = Record<string, unknown>,
  P extends OverlayElementParent = OverlayElementParent,
> = ComponentType<OverlayComponentProps<P | undefined> & T>

/**
 * @public
 */
export declare interface OverlayComponentProps<
  P extends OverlayElementParent = OverlayElementParent,
> extends OverlayComponentResolverContext<P> {
  PointerEvents: FunctionComponent<PropsWithChildren<HTMLAttributes<HTMLDivElement>>>
}

/**
 * @public
 */
export declare type OverlayComponentResolver<
  T extends OverlayComponent = OverlayComponent<Record<string, unknown>, any>,
> = (context: OverlayComponentResolverContext) =>
  | T
  | {
      component: T
      props?: Record<string, unknown>
    }
  | Array<
      | T
      | {
          component: T
          props?: Record<string, unknown>
        }
    >
  | ReactElement
  | undefined
  | void

/**
 * @public
 */
export declare interface OverlayComponentResolverContext<
  P extends OverlayElementParent = OverlayElementParent,
> {
  /**
   * The resolved field's document schema type
   */
  document: DocumentSchema
  /**
   * The element node that the overlay is attached to
   */
  element: ElementNode
  /**
   * The element node that the Sanity node data is detected on
   */
  targetElement: ElementNode
  /**
   * The resolved field schema type
   */
  field: OverlayElementField
  /**
   * Whether the overlay is focused or not
   */
  focused: boolean
  /**
   * The Sanity node data that triggered the overlay
   */
  node: SanityNode
  /**
   * The resolved field's parent schema type
   */
  parent: P
  /**
   * A convience property, equal to `field.value.type`
   */
  type: string
}

export declare type OverlayElementField =
  | SchemaArrayItem
  | SchemaObjectField
  | SchemaUnionOption
  | undefined

export declare type OverlayElementParent =
  | DocumentSchema
  | SchemaNode
  | SchemaArrayItem
  | SchemaUnionOption
  | SchemaUnionNode
  | undefined

/**
 * @public
 */
export declare type OverlayPluginComponent<
  T extends Record<string, unknown> = Record<string, unknown>,
  P extends OverlayElementParent = OverlayElementParent,
> = ComponentType<OverlayComponentResolverContext<P | undefined> & T>

/** @public  */
export declare type OverlayPluginDefinition =
  | OverlayPluginExclusiveDefinition
  | OverlayPluginHudDefinition

/** @public  */
export declare interface OverlayPluginDefinitionBase {
  name: string
  title?: string
  icon?: ComponentType
  guard?: (context: OverlayComponentResolverContext) => boolean
}

/** @public  */
export declare interface OverlayPluginExclusiveDefinition extends OverlayPluginDefinitionBase {
  type: 'exclusive'
  component?: OverlayPluginComponent<
    Record<string, unknown> & {
      closeExclusiveView: () => void
    },
    any
  >
}

/** @public  */
export declare interface OverlayPluginHudDefinition extends OverlayPluginDefinitionBase {
  type: 'hud'
  component?: OverlayPluginComponent<Record<string, unknown>, any>
}

export {SanityNode}

export {SchemaArrayItem}

export {SchemaArrayNode}

export {SchemaBooleanNode}

export {SchemaInlineNode}

export {SchemaNode}

export {SchemaNullNode}

export {SchemaNumberNode}

export {SchemaObjectField}

export {SchemaObjectNode}

export {SchemaStringNode}

export {SchemaUnionNode}

export {SchemaUnionNodeOptions}

export {SchemaUnionOption}

export {SchemaUnknownNode}

/**
 * @public
 */
export declare function VisualEditing(props: VisualEditingProps): React.JSX.Element

/**
 * @public
 */
export declare interface VisualEditingOptions {
  /**
   * @alpha
   * This API is unstable and could change at any time.
   */
  plugins?: OverlayPluginDefinition[]
  /**
   * @alpha
   * This API is unstable and could change at any time.
   */
  components?: OverlayComponentResolver
  /**
   * The history adapter is used for Sanity Presentation to navigate URLs in the preview frame.
   */
  history?: HistoryAdapter
  /**
   * The refresh API allows smarter refresh logic than the default `location.reload()` behavior.
   */
  refresh?: (payload: HistoryRefresh) => false | Promise<void>
  /**
   * The CSS z-index on the root node that renders overlays, tweak it accordingly to what layout you have.
   */
  zIndex?: string | number
}

/**
 * @public
 */
export declare interface VisualEditingProps extends Omit<VisualEditingOptions, 'history'> {
  /**
   * @deprecated The history adapter is already implemented
   */
  history?: never
}

export {WithRequired}

export {}
