import type {ArrayOptions} from '@sanity/types'
import {Path} from '@sanity/client/csm'
import type {PreviewValue} from '@sanity/types'
import type {StudioPathLike} from '@sanity/client/csm'

export declare interface DocumentSchema {
  type: 'document'
  name: string
  title?: string
  icon?: string
  fields: Partial<Record<string, SchemaObjectField>>
}

/** @alpha This API may change */
export declare interface InsertMenuOptions {
  /**
   * @defaultValue `'auto'`
   * `filter: 'auto'` automatically turns on filtering if there are more than 5
   * schema types added to the menu.
   */
  filter?: 'auto' | boolean | undefined
  groups?:
    | Array<{
        name: string
        title?: string
        of?: Array<string>
      }>
    | undefined
  /** defaultValue `true` */
  showIcons?: boolean | undefined
  /** @defaultValue `[{name: 'list'}]` */
  views?:
    | Array<
        | {
            name: 'list'
          }
        | {
            name: 'grid'
            previewImageUrl?: (schemaTypeName: string) => string | undefined
          }
      >
    | undefined
}

export {Path}

/**
 * @public
 */
export declare type PreviewSnapshot = {
  [K in keyof Omit<PreviewValue, 'media'>]?: Omit<PreviewValue, 'media'>[K]
} & {
  _id: string
}

export declare type ResolvedSchemaTypeMap = Map<string, Map<string, StudioPathLike>>

/**
 * Data resolved from a Sanity node
 * @public
 */
export declare type SanityNode = {
  baseUrl: string
  id: string
  path: string
  perspective?: string
  dataset?: string
  projectId?: string
  tool?: string
  type?: string
  workspace?: string
}

/**
 * Data resolved from a Sanity Stega node
 * @public
 */
export declare type SanityStegaNode = {
  origin: string
  href: string
  data?: unknown
}

export declare interface SchemaArrayItem<T extends SchemaNode = SchemaNode> {
  type: 'arrayItem'
  name: string
  title?: string
  value: T
}

export declare interface SchemaArrayNode<T extends SchemaNode = SchemaNode> {
  type: 'array'
  of: SchemaArrayItem<T>
}

export declare interface SchemaBooleanNode {
  type: 'boolean'
  value?: boolean
}

export declare interface SchemaInlineNode {
  type: 'inline'
  /** the name of the referenced type */
  name: string
}

export declare type SchemaNode =
  | SchemaArrayNode
  | SchemaBooleanNode
  | SchemaInlineNode
  | SchemaNullNode
  | SchemaNumberNode
  | SchemaObjectNode
  | SchemaStringNode
  | SchemaUnionNode
  | SchemaUnknownNode

export declare interface SchemaNullNode {
  type: 'null'
}

export declare interface SchemaNumberNode {
  type: 'number'
  value?: number
}

export declare interface SchemaObjectField<T extends SchemaNode = SchemaNode> {
  type: 'objectField'
  name: string
  title?: string
  value: T
  optional?: boolean
}

export declare interface SchemaObjectNode<T extends SchemaNode = SchemaNode> {
  type: 'object'
  fields: Partial<Record<string, SchemaObjectField<T>>>
  rest?: SchemaObjectNode | SchemaUnknownNode | SchemaInlineNode
  dereferencesTo?: string
}

export declare interface SchemaStringNode {
  type: 'string'
  value?: string
}

export declare type SchemaType = DocumentSchema | TypeSchema

export declare interface SchemaUnionNode<T extends SchemaNode = SchemaNode> {
  type: 'union'
  of: SchemaUnionOption<T>[] | SchemaStringNode[] | SchemaNumberNode[]
  options?: SchemaUnionNodeOptions
}

export declare type SchemaUnionNodeOptions = Omit<ArrayOptions, 'insertMenu'> & {
  insertMenu?: Omit<InsertMenuOptions, 'views'> & {
    views?: Array<
      | {
          name: 'list'
        }
      | {
          name: 'grid'
          previewImageUrls?: Record<string, string | undefined>
        }
    >
  }
}

export declare interface SchemaUnionOption<T extends SchemaNode = SchemaNode> {
  type: 'unionOption'
  name: string
  title?: string
  icon?: string
  value: T
}

export declare interface SchemaUnknownNode {
  type: 'unknown'
}

export declare interface TypeSchema {
  type: 'type'
  name: string
  title?: string
  value: SchemaNode
}

export declare interface UnresolvedPath {
  id: string
  path: string
}

export {}
