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

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 OverlayPluginDefinition =
  | OverlayPluginExclusiveDefinition
  | OverlayPluginHudDefinition

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

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

/** @public  */
export declare interface OverlayPluginHudDefinition extends OverlayPluginDefinitionBase {
  type: 'hud'
  component?: OverlayComponent<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 | null

/**
 * @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' | 'refresh'> {
  /**
   * @deprecated The history adapter is already implemented
   */
  history?: never
  /**
   * The refresh API allows smarter refresh logic than the default `location.reload()` behavior.
   * You can call the refreshDefault argument to trigger the default refresh behavior so you don't have to reimplement it.
   */
  refresh?: (
    payload: HistoryRefresh,
    refreshDefault: () => false | Promise<void>,
  ) => false | Promise<void>
}

export {WithRequired}

export {}
