/**
 * Represents an error that occurred during a diff process.
 * Contains `path`, `value` and `serializedPath` properties,
 * which is helpful for debugging and showing friendly messages.
 *
 * @public
 */
export declare class DiffError extends Error {
  path: Path
  value: unknown
  serializedPath: string
  constructor(message: string, path: Path, value?: unknown)
}

/**
 * Diffs two items and returns an array of patches.
 * Note that this is different from `diffPatch`, which generates _mutations_.
 *
 * @param itemA - The first item to compare
 * @param itemB - The second item to compare
 * @param opts - Options for the diff generation
 * @param path - Path to the current item
 * @param patches - Array of patches to append the results to. Note that this is MUTATED.
 * @returns Array of patches
 * @public
 */
export declare function diffItem(
  itemA: unknown,
  itemB: unknown,
  opts?: DiffOptions,
  path?: Path,
  patches?: Patch[],
): Patch[]

/**
 * A `diffMatchPatch` operation
 * Applies the given `value` (unidiff format) to the given path. Must be a string.
 * Note: NOT a serializable mutation, see {@link SanityDiffMatchPatch} for that
 *
 * @public
 */
export declare interface DiffMatchPatch {
  op: 'diffMatchPatch'
  path: Path
  value: string
}

/**
 * Options for the diff-match-patch algorithm.
 *
 * @public
 */
export declare interface DiffMatchPatchOptions {
  /**
   * Whether or not to use diff-match-patch at all
   *
   * @defaultValue `true`
   */
  enabled: boolean
  /**
   * Threshold at which to start using diff-match-patch instead of a regular `set` patch.
   *
   * @defaultValue `30`
   */
  lengthThresholdAbsolute: number
  /**
   * Only use generated diff-match-patch if the patch length is less than or equal to
   * (targetString * relative). Example: A 100 character target with a relative factor
   * of 1.2 will allow a 120 character diff-match-patch. If larger than this number,
   * it will fall back to a regular `set` patch.
   *
   * @defaultValue `1.2`
   */
  lengthThresholdRelative: number
}

/**
 * Options for diff generation, where all DMP properties are required
 *
 * @public
 */
export declare type DiffOptions = PatchOptions & {
  diffMatchPatch: Required<DiffMatchPatchOptions>
}

/**
 * Generates an array of mutations for Sanity, based on the differences between
 * the two passed documents/trees.
 *
 * @param itemA - The first document/tree to compare
 * @param itemB - The second document/tree to compare
 * @param opts - Options for the diff generation
 * @returns Array of mutations
 * @public
 */
export declare function diffPatch(
  itemA: DocumentStub,
  itemB: DocumentStub,
  opts?: PatchOptions,
): SanityPatchMutation[]

/**
 * Represents a partial Sanity document (eg a "stub").
 *
 * @public
 */
export declare interface DocumentStub {
  _id?: string
  _type?: string
  _rev?: string
  _createdAt?: string
  _updatedAt?: string
  [key: string]: unknown
}

/**
 * A `insert` operation
 * Inserts the given items _after_ the given path
 * Note: NOT a serializable mutation, see {@link SanityInsertPatch} for that
 *
 * @public
 */
export declare interface InsertAfterPatch {
  op: 'insert'
  after: Path
  items: any[]
}

/**
 * A patch containing either a Sanity set, unset, insert or diffMatchPatch operation
 *
 * @public
 */
export declare type Patch = SetPatch | UnsetPatch | InsertAfterPatch | DiffMatchPatch

/**
 * Options for the patch generator
 *
 * @public
 */
export declare interface PatchOptions {
  /**
   * Document ID to apply the patch to.
   *
   * @defaultValue `undefined` - tries to extract `_id` from passed document
   */
  id?: string
  /**
   * Base path to apply the patch to - useful if diffing sub-branches of a document.
   *
   * @defaultValue `[]` - eg root of the document
   */
  basePath?: Path
  /**
   * Only apply the patch if the document revision matches this value.
   * If the property is the boolean value `true`, it will attempt to extract
   * the revision from the document `_rev` property.
   *
   * @defaultValue `undefined` (do not apply revision check)
   */
  ifRevisionID?: string | true
  /**
   * Whether or not to hide warnings during the diff process.
   *
   * @defaultValue `false`
   */
  hideWarnings?: boolean
  /**
   * Options for the diff-match-patch algorithm.
   */
  diffMatchPatch?: Partial<DiffMatchPatchOptions>
}

/**
 * An array of path segments representing a path in a document
 *
 * @public
 */
export declare type Path = PathSegment[]

/**
 * A segment of a path
 *
 * @public
 */
export declare type PathSegment =
  | string
  | number
  | {
      _key: string
    }
  | [number | '', number | '']

/**
 * A Sanity `diffMatchPatch` patch mutation operation
 * Patches the given path with the given unidiff string.
 *
 * @public
 */
export declare interface SanityDiffMatchPatch {
  id: string
  diffMatchPatch: {
    [key: string]: string
  }
}

/**
 * A Sanity `insert` patch mutation operation
 * Inserts the given items at the given path (before/after)
 *
 * @public
 */
export declare interface SanityInsertPatch {
  id: string
  insert:
    | {
        before: string
        items: any[]
      }
    | {
        after: string
        items: any[]
      }
    | {
        replace: string
        items: any[]
      }
}

/**
 * A patch containing either a set, unset, insert or diffMatchPatch operation
 *
 * @public
 */
export declare type SanityPatch =
  | SanitySetPatch
  | SanityUnsetPatch
  | SanityInsertPatch
  | SanityDiffMatchPatch

/**
 * A mutation containing a single patch
 *
 * @public
 */
export declare interface SanityPatchMutation {
  patch: SanityPatch
}

/**
 * A Sanity `set` patch mutation operation
 * Replaces the current path, does not merge
 *
 * @public
 */
export declare interface SanitySetPatch {
  id: string
  set: {
    [key: string]: any
  }
}

/**
 * A Sanity `unset` patch mutation operation
 * Unsets the entire value of the given path
 *
 * @public
 */
export declare interface SanityUnsetPatch {
  id: string
  unset: string[]
}

/**
 * A `set` operation
 * Replaces the current path, does not merge
 * Note: NOT a serializable mutation, see {@link SanitySetPatch} for that
 *
 * @public
 */
export declare interface SetPatch {
  op: 'set'
  path: Path
  value: unknown
}

/**
 * A `unset` operation
 * Unsets the entire value of the given path
 * Note: NOT a serializable mutation, see {@link SanityUnsetPatch} for that
 *
 * @public
 */
export declare interface UnsetPatch {
  op: 'unset'
  path: Path
}

export {}
