import {ClientPerspective} from '@sanity/client'
import {ComponentType} from 'react'
import {Dispatch} from 'react'
import {DocumentStore} from 'sanity'
import {Observable} from 'rxjs'
import {Plugin as Plugin_2} from 'sanity'
import {PreviewUrlResolver} from '@sanity/preview-url-secret/define-preview-url'
import {PreviewUrlResolverOptions} from '@sanity/preview-url-secret/define-preview-url'
import {RefObject} from 'react'
import {SanityClient} from 'sanity'
import {Serializable} from '@sanity/presentation-comlink'
import {SerializableArray} from '@sanity/presentation-comlink'
import {SerializableObject} from '@sanity/presentation-comlink'
import {SerializablePrimitive} from '@sanity/presentation-comlink'
import {StackablePerspective} from '@sanity/client'

/** @public */
export declare const ACTION_IFRAME_LOADED = 'ACTION_IFRAME_LOADED'

/** @public */
export declare const ACTION_IFRAME_REFRESH = 'ACTION_IFRAME_REFRESH'

/** @public */
export declare const ACTION_IFRAME_RELOAD = 'ACTION_IFRAME_RELOAD'

/** @public */
export declare const ACTION_VISUAL_EDITING_OVERLAYS_TOGGLE = 'ACTION_VISUAL_EDITING_OVERLAYS_TOGGLE'

/**
 * All possible URL search parameters used by the Presentation tool
 * @public
 */
export declare interface CombinedSearchParams
  extends StructureDocumentPaneParams,
    PresentationSearchParams,
    InspectorTab {}

/** @public */
export declare type ConnectionStatus = 'connected' | 'connecting' | 'reconnecting' | 'idle'

/**
 * @public
 */
export declare type ContextFn<T> = (context: DocumentResolverContext) => T

/**
 * Define documents for a given location.
 * This function doesn't do anything itself, it is used to provide type information.
 * @param resolvers - resolvers that return documents.
 * @public
 */
export declare function defineDocuments(resolvers: DocumentResolver[]): typeof resolvers

/**
 * Define locations for a given document type.
 * This function doesn't do anything itself, it is used to provide type information.
 * @param resolver - resolver that return locations for a document.
 * @public
 */
export declare function defineLocations<K extends string>(
  resolver: DocumentLocationResolverObject<K> | DocumentLocationsState,
): typeof resolver

/** @public */
export declare type DispatchPresentationAction = Dispatch<Readonly<PresentationAction>>

/**
 * Represents a document location
 * @param title - Title of the document
 * @param href - URL of the document location
 * @public
 */
export declare interface DocumentLocation {
  title: string
  href: string
}

/**
 * Function used for advanced document location resolution
 * @param params - Object with document `id` and document `type` properties
 * @param context - Object with `documentStore` property for creating listenQuery subscriptions
 * @returns Document location state, optionally as an Observable, or null/undefined if no locations are available
 * @public
 */
export declare type DocumentLocationResolver = (
  params: {
    id: string
    type: string
    version: string | undefined
    perspectiveStack: StackablePerspective[]
  },
  context: {
    documentStore: DocumentStore
  },
) =>
  | DocumentLocationsState
  | null
  | undefined
  | Observable<DocumentLocationsState | null | undefined>

/**
 * Document location resolver object
 * @param select - object for selecting document fields
 * @param resolve - function that accepts a document with the selected fields and returns an optional document location state
 * @public
 */
export declare type DocumentLocationResolverObject<K extends string = string> = {
  select: Record<K, string>
  resolve: (value: Record<K, any> | null) => DocumentLocationsState | null | undefined | void
}

/**
 * Object of document location resolver definitions per document type
 * @public
 */
export declare type DocumentLocationResolvers = Record<
  string,
  DocumentLocationResolverObject | DocumentLocationsState
>

/**
 * State for describing document locations or providing a message if no document
 * locations are unavailable
 * @param locations - Array of document locations
 * @param message - Message to display if locations are unavailable
 * @param tone - Tone of the message
 * @public
 */
export declare interface DocumentLocationsState {
  locations?: DocumentLocation[]
  message?: string
  tone?: 'positive' | 'caution' | 'critical'
}

/**
 * Object for resolving a document for a given route pattern
 * @public
 */
export declare type DocumentResolver =
  | {
      route: string | Array<string>
      type: string
      filter?: never
      params?: never
      resolve?: never
    }
  | {
      route: string | Array<string>
      type?: never
      filter: ContextFn<string> | string
      params?: ContextFn<Record<string, string>> | Record<string, string>
      resolve?: never
    }
  | {
      route: string | Array<string>
      type?: never
      filter?: never
      params?: never
      resolve: ContextFn<
        | {
            filter: string
            params?: Record<string, string>
          }
        | undefined
      >
    }

/**
 * @public
 */
export declare interface DocumentResolverContext {
  origin: string | undefined
  params: Record<string, string>
  path: string
}

/** @public */
export declare interface HeaderOptions {
  component: ComponentType<PreviewHeaderProps>
}

/** @public */
export declare interface IframeLoadedAction {
  type: typeof ACTION_IFRAME_LOADED
}

/** @public */
export declare interface IframeRefreshAction {
  type: typeof ACTION_IFRAME_REFRESH
}

/** @public */
export declare interface IframeReloadAction {
  type: typeof ACTION_IFRAME_RELOAD
}

/**
 * parameters for the changes inspector
 * @public
 */
export declare interface InspectorTab {
  changesInspectorTab?: 'history' | 'review'
}

/** @public */
export declare interface NavigatorOptions {
  minWidth?: number
  maxWidth?: number
  component: ComponentType
}

/** @public */
export declare type PresentationAction =
  | IframeLoadedAction
  | IframeRefreshAction
  | IframeReloadAction
  | VisualEditingOverlaysToggleAction

/** @public */
export declare type PresentationNavigateContextValue = (
  preview: string | undefined,
  document?: {
    type: string
    id: string
  },
) => void

/**
 * All possible parameters that can be used to describe the state of the
 * Presentation tool, stored in the pathname and as search parameters of the URL
 * @public
 */
export declare interface PresentationParams
  extends PresentationStateParams,
    CombinedSearchParams,
    InspectorTab {}

/** @public */
export declare type PresentationPerspective = Exclude<ClientPerspective, 'raw'>

/**
 * @public
 */
export declare interface PresentationPluginOptions {
  devMode?: boolean | (() => boolean)
  icon?: ComponentType
  name?: string
  title?: string
  /**
   * @deprecated use `resolve.locations` instead
   */
  locate?: DocumentLocationResolver
  resolve?: {
    mainDocuments?: DocumentResolver[]
    locations?: DocumentLocationResolvers | DocumentLocationResolver
  }
  previewUrl: PreviewUrlOption
  components?: {
    unstable_header?: HeaderOptions
    unstable_navigator?: NavigatorOptions
  }
  /**
   * @deprecated this feature flag is no longer needed
   */
  unstable_showUnsafeShareUrl?: boolean
}

/**
 * Presentation specific URL search parameters, they should persist when
 * navigating between the document pane and document list pane
 * @public
 */
export declare interface PresentationSearchParams {
  preview?: string
  perspective?: string
  viewport?: string
}

/** @public */
export declare interface PresentationState {
  mainDocument: boolean
  iframe: {
    status: 'loading' | 'loaded' | 'refreshing' | 'reloading'
  }
  visualEditing: {
    overlaysEnabled: boolean
  }
}

/**
 * Presentation specific state that is stored in the pathname section of the URL
 * @public
 */
export declare interface PresentationStateParams {
  type?: string
  id?: string
  path?: string
}

/** @public */
export declare const presentationTool: Plugin_2<PresentationPluginOptions>

/** @public */
export declare type PresentationViewport = 'desktop' | 'mobile'

/** @public */
export declare interface PreviewHeaderProps extends PreviewProps {
  iframeRef: RefObject<HTMLIFrameElement | null>
  renderDefault: (props: PreviewHeaderProps) => React.JSX.Element
}

/** @public */
export declare interface PreviewProps extends Pick<PresentationState, 'iframe' | 'visualEditing'> {
  canSharePreviewAccess: boolean
  canToggleSharePreviewAccess: boolean
  canUseSharedPreviewAccess: boolean
  dispatch: DispatchPresentationAction
  header?: HeaderOptions
  initialUrl: URL
  loadersConnection: ConnectionStatus
  navigatorEnabled: boolean
  onPathChange: (nextPath: string) => void
  onRefresh: (fallback: () => void) => void
  openPopup: (url: string) => void
  overlaysConnection: ConnectionStatus
  perspective: PresentationPerspective
  previewUrl?: string
  setViewport: (mode: 'desktop' | 'mobile') => void
  targetOrigin: string
  toggleNavigator?: () => void
  toggleOverlay: () => void
  viewport: PresentationViewport
  vercelProtectionBypass: string | null
}

/** @public */
export declare type PreviewUrlOption =
  | string
  | PreviewUrlResolver<SanityClient>
  | PreviewUrlResolverOptions

export {PreviewUrlResolver}

export {PreviewUrlResolverOptions}

export {Serializable}

export {SerializableArray}

export {SerializableObject}

export {SerializablePrimitive}

/**
 * Document Pane specific URL search parameters, they should not persist when
 * navigating between the document pane and document list pane
 * @public
 */
export declare interface StructureDocumentPaneParams extends InspectorTab {
  inspect?: string
  path?: string
  rev?: string
  since?: string
  template?: string
  templateParams?: string
  view?: string
  pathKey?: string
  instruction?: string
  comment?: string
}

/** @public */
export declare function usePresentationNavigate(): PresentationNavigateContextValue

/** @public */
export declare function usePresentationParams(throwOnMissingContext?: true): PresentationParams

/** @public */
export declare function usePresentationParams(
  throwOnMissingContext: false,
): PresentationParams | null

/** @public */
export declare const useSharedState: (key: string, value: Serializable) => undefined

/** @public */
export declare interface VisualEditingOverlaysToggleAction {
  type: typeof ACTION_VISUAL_EDITING_OVERLAYS_TOGGLE
  enabled: boolean
}

export {}
