import type {ArrayFieldProps} from 'sanity'
import type {FieldDefinition} from 'sanity'
import {JSX} from 'react'
import type {ObjectFieldProps} from 'sanity'
import {Plugin as Plugin_2} from 'sanity'
import type {Reference} from 'sanity'
import type {SanityDocument} from 'sanity'
import type {useClient} from 'sanity'

/**
 * Input component that replaces Sanity's default array field input with a
 * hierarchical taxonomy tree browser. Studio users can browse taxonomy terms
 * organized in their scheme hierarchy and select terms to add to the array field.
 *
 * @remarks
 * - Must be used with a `schemeFilter` or `branchFilter` helper in the field's
 *   `options.filter`. Rendering without a filter will display a configuration warning.
 * - Supports only **single-schema arrays** (i.e., `of: [{type: 'reference'}]`). Arrays
 *   with multiple schema types will render a warning and fall back to the default input.
 * - Taxonomy selection is disabled when viewing the published perspective.
 * - When `browseOnly` is set in the filter configuration, Sanity's default search input
 *   is suppressed and only the tree browser is available for term selection.
 * - When `expanded` is set in the filter configuration, the hierarchy tree loads open
 *   by default instead of collapsed.
 *
 * @param props - Standard Sanity `ArrayFieldProps` extended with an optional
 *   `embeddingsIndex` configuration object.
 * @param props.embeddingsIndex - Optional configuration for AI-assisted term
 *   recommendations via a Sanity Embeddings Index. When provided, opening the tree
 *   browser queries the specified index and annotates matching taxonomy terms with
 *   a relevance score to help authors identify the most appropriate terms.
 * @param props.embeddingsIndex.indexName - The name of the Sanity Embeddings Index
 *   to query. Must be an index that includes `skosConcept` documents.
 * @param props.embeddingsIndex.fieldReferences - An array of field names from the
 *   current document whose values are concatenated and sent as the embeddings search
 *   query. All listed fields must contain values when the tree browser is opened;
 *   empty fields will display an error message in the tree view rather than scores.
 * @param props.embeddingsIndex.maxResults - Maximum number of semantically matching
 *   terms to return from the embeddings index. Defaults to `3`.
 *
 * @example
 * Basic usage with a scheme filter:
 * ```js
 * import {ArrayHierarchyInput, schemeFilter} from 'sanity-plugin-taxonomy-manager'
 *
 * defineField({
 *   name: 'categories',
 *   title: 'Categories',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'reference',
 *       to: {type: 'skosConcept'},
 *       options: {
 *         filter: schemeFilter({schemeId: 'f3deba'}),
 *         disableNew: true,
 *       },
 *     },
 *   ],
 *   components: {field: ArrayHierarchyInput},
 * })
 * ```
 *
 * @example
 * Branch filter with tree expanded by default:
 * ```js
 * import {ArrayHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
 *
 * defineField({
 *   name: 'habitats',
 *   title: 'Habitats',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'reference',
 *       to: {type: 'skosConcept'},
 *       options: {
 *         filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', expanded: true}),
 *         disableNew: true,
 *       },
 *     },
 *   ],
 *   components: {field: ArrayHierarchyInput},
 * })
 * ```
 *
 * @example
 * Browse-only mode (suppresses the default Sanity search input):
 * ```js
 * import {ArrayHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
 *
 * defineField({
 *   name: 'habitats',
 *   title: 'Habitats',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'reference',
 *       to: {type: 'skosConcept'},
 *       options: {
 *         filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', browseOnly: true}),
 *         disableNew: true,
 *       },
 *     },
 *   ],
 *   components: {field: ArrayHierarchyInput},
 * })
 * ```
 *
 * @example
 * AI-assisted recommendations via an embeddings index:
 * ```jsx
 * import {ArrayHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
 *
 * defineField({
 *   name: 'categories',
 *   title: 'Categories',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'reference',
 *       to: [{type: 'skosConcept'}],
 *       options: {
 *         filter: branchFilter({schemeId: 'f3deba', branchId: '25f826'}),
 *         disableNew: true,
 *       },
 *     },
 *   ],
 *   components: {
 *     field: (props) => (
 *       <ArrayHierarchyInput
 *         {...props}
 *         embeddingsIndex={{
 *           indexName: 'my-taxonomy-index',
 *           fieldReferences: ['title', 'description'],
 *           maxResults: 4,
 *         }}
 *       />
 *     ),
 *   },
 * })
 * ```
 *
 * @see {@link ReferenceHierarchyInput} for single-value `reference` fields
 * @see {@link schemeFilter} for filtering by a full concept scheme
 * @see {@link branchFilter} for filtering by a branch within a concept scheme
 */
export declare function ArrayHierarchyInput(props: ArrayHierarchyInputProps): JSX.Element

declare type ArrayHierarchyInputProps = ArrayFieldProps & {
  embeddingsIndex?: EmbeddingsIndexConfig
}

/**
 * #### Reference Field Scheme & Branch Filter
 * A pluggable Function for Filtering to a Top Concept Branch within a SKOS Concept Scheme
 * @param {string} schemeId - The unique six character concept identifier for
 *   the Concept Scheme to which you wish to filter.
 * @param {string} branchId - The unique six character concept identifier of
 *   a branch. Child concepts will be returned.
 * @param {boolean} [expanded] - Set to `true` to display open hierarchy trees for
 *   input components. Input component trees load closed by default.
 * @param {boolean} [browseOnly] - Set to `true` to hide the default Sanity search
 *   input and display only the "Browse Taxonomy Tree" button for selecting terms.
 * @returns A reference type filter for the child concepts of the designated branch in the selected Concept Scheme
 * @example
 * ```ts
 * import { branchFilter } from 'sanity-plugin-taxonomy-manager'
 * ...
 * {
 *   name: 'test',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'reference',
 *       to: {type: 'skosConcept'},
 *       options: {
 *         filter: branchFilter({
 *            schemeId: 'a1b2c3',
 *            branchId: 'd4e5f6',
 *            expanded: true, // optional; defaults to false (closed tree)
 *            browseOnly: true, // optional; hides search input
 *        }),
 *         disableNew: true,
 *       },
 *     },
 *   ],
 * }
 * ```
 */
export declare const branchFilter: (
  options: BranchOptions,
) => ({
  getClient,
}: {
  getClient: (clientOptions: {apiVersion: string}) => ReturnType<typeof useClient>
}) => Promise<BranchFilterResult>

declare type BranchFilterResult = {
  filter: string
  params: {
    schemeId: string
    branchId: string
    concepts: string[]
  }
  expanded?: boolean
  browseOnly?: boolean
}

declare type BranchOptions = {
  schemeId: string
  branchId: string
  expanded?: boolean
  browseOnly?: boolean
}

declare interface ConceptSchemeDocument extends SanityDocument {
  displayed: {
    _id: string
    _type: 'skosConceptScheme'
    title?: string
    description?: string
    baseIri?: string
    schemeId?: string
    topConcepts?: Array<{
      _key: string
      _ref: string
      _type: 'reference'
    }>
    concepts?: Array<{
      _key: string
      _ref: string
      _type: 'reference'
    }>
  }
}

declare interface EmbeddingsIndexConfig {
  indexName: string
  fieldReferences: string[]
  maxResults?: number
}

declare interface EmbeddingsResult {
  score: number
  value: {
    documentId: string
    type: string
  }
}

declare type HierarchyInput = ObjectFieldProps<Reference> & {
  embeddingsIndex?: EmbeddingsIndexConfig
}

declare interface Options {
  baseUri?: string
  customConceptFields?: FieldDefinition[]
  customSchemeFields?: FieldDefinition[]
  ident?: {
    pattern?: string
    length?: number
    prefix?: string
    regenUi?: boolean
  }
}

/**
 * Input component that replaces Sanity's default reference field input with a
 * hierarchical taxonomy tree browser. Studio users can browse taxonomy terms
 * organized in their scheme hierarchy and select a single term for the field.
 *
 * @remarks
 * - Must be used with a `schemeFilter` or `branchFilter` helper in the field's
 *   `options.filter`. Rendering without a filter will display a configuration warning.
 * - Taxonomy selection is disabled when viewing the published perspective.
 * - When `browseOnly` is set in the filter configuration, Sanity's default search input
 *   is suppressed and only the tree browser is available for term selection.
 * - When `expanded` is set in the filter configuration, the hierarchy tree loads open
 *   by default instead of collapsed.
 *
 * @param props - Standard Sanity `ObjectFieldProps<Reference>` extended with an optional
 *   `embeddingsIndex` configuration object.
 * @param props.embeddingsIndex - Optional configuration for AI-assisted term
 *   recommendations via a Sanity Embeddings Index. When provided, opening the tree
 *   browser queries the specified index and annotates matching taxonomy terms with
 *   a relevance score to help authors identify the most appropriate term.
 * @param props.embeddingsIndex.indexName - The name of the Sanity Embeddings Index
 *   to query. Must be an index that includes `skosConcept` documents.
 * @param props.embeddingsIndex.fieldReferences - An array of field names from the
 *   current document whose values are concatenated and sent as the embeddings search
 *   query. All listed fields must contain values when the tree browser is opened;
 *   empty fields will display an error message in the tree view rather than scores.
 * @param props.embeddingsIndex.maxResults - Maximum number of semantically matching
 *   terms to return from the embeddings index. Defaults to `3`.
 *
 * @example
 * Basic usage with a scheme filter:
 * ```js
 * import {ReferenceHierarchyInput, schemeFilter} from 'sanity-plugin-taxonomy-manager'
 *
 * defineField({
 *   name: 'gradeLevel',
 *   title: 'Grade Level',
 *   type: 'reference',
 *   to: {type: 'skosConcept'},
 *   options: {
 *     filter: schemeFilter({schemeId: 'f3deba'}),
 *     disableNew: true,
 *   },
 *   components: {field: ReferenceHierarchyInput},
 * })
 * ```
 *
 * @example
 * Branch filter with tree expanded by default:
 * ```js
 * import {ReferenceHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
 *
 * defineField({
 *   name: 'topics',
 *   title: 'Topics',
 *   type: 'reference',
 *   to: {type: 'skosConcept'},
 *   options: {
 *     filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', expanded: true}),
 *     disableNew: true,
 *   },
 *   components: {field: ReferenceHierarchyInput},
 * })
 * ```
 *
 * @example
 * Browse-only mode (suppresses the default Sanity search input):
 * ```js
 * import {ReferenceHierarchyInput, branchFilter} from 'sanity-plugin-taxonomy-manager'
 *
 * defineField({
 *   name: 'topics',
 *   title: 'Topics',
 *   type: 'reference',
 *   to: {type: 'skosConcept'},
 *   options: {
 *     filter: branchFilter({schemeId: 'cf76c1', branchId: '1e5e6c', browseOnly: true}),
 *     disableNew: true,
 *   },
 *   components: {field: ReferenceHierarchyInput},
 * })
 * ```
 *
 * @example
 * AI-assisted recommendations via an embeddings index:
 * ```jsx
 * import {ReferenceHierarchyInput, schemeFilter} from 'sanity-plugin-taxonomy-manager'
 *
 * defineField({
 *   name: 'topics',
 *   title: 'Topics',
 *   type: 'reference',
 *   to: [{type: 'skosConcept'}],
 *   options: {
 *     filter: schemeFilter({schemeId: 'f3deba'}),
 *     disableNew: true,
 *   },
 *   components: {
 *     field: (props) => (
 *       <ReferenceHierarchyInput
 *         {...props}
 *         embeddingsIndex={{
 *           indexName: 'my-taxonomy-index',
 *           fieldReferences: ['title', 'metaDescription'],
 *           maxResults: 4,
 *         }}
 *       />
 *     ),
 *   },
 * })
 * ```
 *
 * @see {@link ArrayHierarchyInput} for multi-value `array` fields
 * @see {@link schemeFilter} for filtering by a full concept scheme
 * @see {@link branchFilter} for filtering by a branch within a concept scheme
 */
export declare function ReferenceHierarchyInput(props: HierarchyInput): JSX.Element

/**
 * #### Reference Field Scheme Filter
 * Pluggable Function for Filtering to a Single SKOS Concept Scheme.
 * @param {string} schemeId - The unique six character concept identifier for
 *   the Concept Scheme to which you wish to filter.
 * @param {boolean} [expanded] - Set to `true` to display open hierarchy trees for
 *   input components. Input component trees load closed by default.
 * @param {boolean} [browseOnly] - Set to `true` to hide the default Sanity search
 *   input and display only the "Browse Taxonomy Tree" button for selecting terms.
 * @returns A reference type filter for Concepts and Top Concepts in
 *   the selected Concept Scheme test
 * @example
 * ```ts
 * import { schemeFilter } from 'sanity-plugin-taxonomy-manager'
 * ...
 * {
 *   name: 'test',
 *   type: 'array',
 *   of: [
 *     {
 *       type: 'reference',
 *       to: {type: 'skosConcept'},
 *       options: {
 *         filter: schemeFilter({
 *            schemeId: 'a1b2c3',
 *            expanded: true, // optional; defaults to false (closed tree)
 *            browseOnly: true, // optional; hides search input
 *          }),
 *         disableNew: true,
 *       },
 *     },
 *   ],
 * }
 * ```
 */
export declare const schemeFilter: (
  options: SchemeOptions,
) => ({
  getClient,
}: {
  getClient: (clientOptions: {apiVersion: string}) => ReturnType<typeof useClient>
}) => Promise<SchemeFilterResult>

declare type SchemeFilterResult = {
  filter: string
  params: {
    schemeId: string
    concepts: string[]
    topConcepts: string[]
  }
  expanded?: boolean
  browseOnly?: boolean
}

declare type SchemeOptions = {
  schemeId: string
  expanded?: boolean
  browseOnly?: boolean
}

/**
 * #### Sanity Taxonomy Manager
 * Defines a Sanity plugin for managing SKOS compliant taxonomies in Sanity Studio.
 * #### Options
 * @param baseUri - The base URI to use for SKOS concepts and concept schemes. BaseURI should follow an IANA http/s scheme and should terminate with either a / or #.
 * @param customConceptFields - An array of additional fields to add to the skosConcept type.
 * @param customSchemeFields - An array of additional fields to add to the skosConceptScheme type.
 * #### Identifier Configuration
 * @param ident.pattern - The character set to use for identifiers (default: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz').
 * @param ident.length - The length of the generated identifier (default: 6).
 * @param ident.prefix - A prefix to prepend to generated identifiers, for example to use Wikidata style IDs like "Q27521" (default: '').
 * @param ident.regenUi - Whether to display the "Create Unique Identifier" button in the UI by default.
 * @returns A Sanity plugin object.
 */
export declare const taxonomyManager: Plugin_2<Options | undefined>

/**
 * #### Tree View Component Wrapper
 * This is the view component for the hierarchy tree. It is the
 * top level of concept scheme views and is passed into Desk
 * structure to render the primary view for taxonomy documents.
 * @param document - The document to render.
 * @param branchId - The branch ID to fetch concepts from.
 * @param inputComponent - Specifies whether the component is Studio input component, which will hide tree view controls and chrome.
 * @param selectConcept - The function to call when a concept is selected.
 */
export declare const TreeView: ({
  document,
  branchId,
  inputComponent,
  selectConcept,
  expanded,
  conceptRecs,
  recsError,
}: TreeViewProps) => JSX.Element

declare interface TreeViewProps {
  document?: ConceptSchemeDocument
  branchId?: string | null
  selectConcept?: (conceptId: {_ref: string; _type: 'reference'; _originalId?: string}) => void
  inputComponent?: boolean
  expanded?: boolean
  conceptRecs?: EmbeddingsResult[]
  recsError?: string | null
}

export {}
