import {CardProps} from '@sanity/ui'
import {MouseEvent as MouseEvent_2} from 'react'
import {TooltipProps} from '@sanity/ui'

/** @public */
declare interface APICallSignature {
  _type: 'api.callSignature'
  comment?: TSDocComment
  parameters: SanityArrayItem<APIParameter>[]
  releaseTag?: APIReleaseTag
  returnType: SanityArrayItem<APIToken>[]
  typeParameters: SanityArrayItem<APITypeParameter>[]
}

/** @public */
declare interface APIClass {
  _id?: string
  _type: 'api.class'
  comment?: TSDocComment
  export: APIExport
  isReactComponentType: boolean
  members: SanityArrayItem<APIConstructor | APIProperty | APIMethod>[]
  name: string
  package: APIPackage
  release: APIRelease
  releaseTag?: APIReleaseTag
  slug: SanitySlugValue
  typeParameters: SanityArrayItem<APITypeParameter>[]
}

/** @public */
declare interface APIConstructor {
  _type: 'api.constructor'
  comment?: TSDocComment
  parameters: SanityArrayItem<APIParameter>[]
  releaseTag?: APIReleaseTag
}

/** @public */
declare interface APIConstructSignature {
  _type: 'api.constructSignature'
  comment?: TSDocComment
  parameters: SanityArrayItem<APIParameter>[]
  releaseTag?: APIReleaseTag
  returnType: SanityArrayItem<APIToken>[]
  typeParameters: SanityArrayItem<APITypeParameter>[]
}

/** @public */
declare type APIDocument =
  | APIMemberDocument
  | APIPackageDocument
  | APIReleaseDocument
  | APIExportDocument
  | APISymbolDocument

/** @public */
declare interface APIEnum {
  _id?: string
  _type: 'api.enum'
  comment?: TSDocComment
  export: APIExport
  members: SanityArrayItem<APIEnumMember>[]
  name: string
  package: APIPackage
  release: APIRelease
  releaseTag?: APIReleaseTag
  slug: SanitySlugValue
}

/** @public */
declare interface APIEnumMember {
  _type: 'api.enumMember'
  name: string
  releaseTag?: APIReleaseTag
}

/** @public */
declare interface APIExport {
  _type: 'api.export'
  members: SanityArrayItem<APIMember>[]
  name: string
  package: APIPackage
  path: string
  release: APIRelease
}

/** @public */
declare type APIExportDocument = SanityDocumentValue<SerializedAPIExport>

/** @public */
declare interface APIFunction {
  _id?: string
  _type: 'api.function'
  comment?: TSDocComment
  export: APIExport
  isReactComponentType: boolean
  isReactHook: boolean
  isOverloading: boolean
  name: string
  package: APIPackage
  parameters: SanityArrayItem<APIParameter>[]
  propsType?: APIInterface
  release: APIRelease
  releaseTag?: APIReleaseTag
  returnType: SanityArrayItem<APIToken>[]
  slug: SanitySlugValue
  typeParameters: SanityArrayItem<APITypeParameter>[]
}

/** @public */
declare interface APIIndexSignature {
  _type: 'api.indexSignature'
  comment?: TSDocComment
  parameters: SanityArrayItem<APIParameter>[]
  releaseTag?: APIReleaseTag
  returnType: SanityArrayItem<APIToken>[]
}

/** @public */
declare interface APIInterface {
  _id?: string
  _type: 'api.interface'
  comment?: TSDocComment
  export: APIExport
  extends: {
    _type: 'api.extend'
    type: SanityArrayItem<APIToken>[]
  }[]
  members: SanityArrayItem<
    | APICallSignature
    | APIConstructSignature
    | APIMethodSignature
    | APIPropertySignature
    | APIIndexSignature
  >[]
  name: string
  package: APIPackage
  release: APIRelease
  releaseTag?: APIReleaseTag
  slug: SanitySlugValue
  typeParameters: SanityArrayItem<APITypeParameter>[]
}

/** @public */
declare type APIMember =
  | APIClass
  | APIEnum
  | APIFunction
  | APIInterface
  | APINamespace
  | APITypeAlias
  | APIVariable

/** @public */
declare type APIMemberDocument = SanityDocumentValue<SerializedAPIMember>

/** @public */
declare interface APIMethod {
  _type: 'api.method'
  comment?: TSDocComment
  isOptional: boolean
  isStatic: boolean
  name: string
  parameters: SanityArrayItem<APIParameter>[]
  releaseTag?: APIReleaseTag
  returnType: SanityArrayItem<APIToken>[]
  typeParameters: SanityArrayItem<APITypeParameter>[]
}

/** @public */
declare interface APIMethodSignature {
  _type: 'api.methodSignature'
  comment?: TSDocComment
  isOptional: boolean
  name: string
  parameters: SanityArrayItem<APIParameter>[]
  releaseTag?: APIReleaseTag
  returnType: SanityArrayItem<APIToken>[]
  typeParameters: SanityArrayItem<APITypeParameter>[]
}

/** @public */
declare interface APINamespace {
  _id?: string
  _type: 'api.namespace'
  comment?: TSDocComment
  export: APIExport
  members: SanityArrayItem<APIMember>[]
  name: string
  package: APIPackage
  release: APIRelease
  releaseTag?: APIReleaseTag
  slug: SanitySlugValue
}

/** @public */
declare interface APIPackage {
  _type: 'api.package'
  scope?: string
  name: string
  latestRelease: APIRelease
  releases: APIRelease[]
}

/** @public */
declare type APIPackageDocument = SanityDocumentValue<SerializedAPIPackage>

/** @public */
declare interface APIParameter {
  _type: 'api.parameter'
  comment?: TSDocComment
  name: string
  releaseTag?: APIReleaseTag
  type: SanityArrayItem<APIToken>[]
  isOptional: boolean
}

/** @public */
declare interface APIProperty {
  _type: 'api.property'
  comment?: TSDocComment
  isEventProperty: boolean
  isOptional: boolean
  isStatic: boolean
  name: string
  releaseTag?: APIReleaseTag
  type: SanityArrayItem<APIToken>[]
}

/** @public */
declare interface APIPropertySignature {
  _type: 'api.propertySignature'
  comment?: TSDocComment
  isOptional: boolean
  name: string
  releaseTag?: APIReleaseTag
  type: SanityArrayItem<APIToken>[]
}

/** @public */
declare interface APIRelease {
  _type: 'api.release'
  exports: SanityArrayItem<APIExport>[]
  package: APIPackage
  memberNames: string[]
  version: string
}

/** @public */
declare type APIReleaseDocument = SanityDocumentValue<SerializedAPIRelease>

/** @public */
declare type APIReleaseTag = 'internal' | 'alpha' | 'beta' | 'public' | 'experimental'

/** @public */
declare interface APISymbol {
  _type: 'api.symbol'
  name: string
  package: APIPackage
}

/** @public */
declare type APISymbolDocument = SanityDocumentValue<SerializedAPISymbol>

/** @public */
declare interface APIToken {
  _type: 'api.token'
  member?: APIMember & {
    _id: string
  }
  text: string
}

/** @public */
declare interface APITypeAlias {
  _id?: string
  _type: 'api.typeAlias'
  comment?: TSDocComment
  export: APIExport
  name: string
  package: APIPackage
  release: APIRelease
  releaseTag?: APIReleaseTag
  slug: SanitySlugValue
  type: SanityArrayItem<APIToken>[]
  typeParameters: SanityArrayItem<APITypeParameter>[]
}

/** @public */
declare interface APITypeParameter {
  _type: 'api.typeParameter'
  constraintType?: SanityArrayItem<APIToken>[]
  defaultType: SanityArrayItem<APIToken>[]
  name: string
}

/** @public */
declare interface APIVariable {
  _id?: string
  _type: 'api.variable'
  comment?: TSDocComment
  export: APIExport
  isReactComponentType: boolean
  name: string
  package: APIPackage
  propsType?: APIMember
  release: APIRelease
  releaseTag?: APIReleaseTag
  slug: SanitySlugValue
  type: SanityArrayItem<APIToken>[]
}

/** @beta */
export declare function mount(options: {
  docs: APIDocument[]
  releaseVersion?: string
  element: HTMLElement | null
}): void

/** @beta */
export declare function parsePath(
  path: string,
  options?: {
    basePath?: string
    version?: string
  },
): TSDocAppParams

/**
 * @public
 */
declare interface PortableTextBlockNode {
  _type: 'block'
  style: string
  children: SanityArrayItem<PortableTextNode>[]
  markDefs: SanityArrayItem<PortableTextSpanNode['_markDef']>[]
}

/**
 * @public
 */
declare interface PortableTextCodeNode {
  _type: 'code'
  code: string
  language: string
}

/**
 * @public
 */
declare type PortableTextNode = PortableTextSpanNode | PortableTextCodeNode | PortableTextBlockNode

/**
 * @public
 */
declare interface PortableTextSpanNode {
  _type: 'span'
  _markDef?: {
    _key?: string
    _type: 'link'
    href: string
  }
  marks?: string[]
  text: string
}

/** @alpha */
export declare function ReferenceTooltip(props: {
  children: React.ReactElement<any>
  member: APIMember
}): React.ReactNode

/** @alpha */
export declare function ReferenceTooltipContent(props: {data: APIMember}): React.ReactNode

/** @public */
declare type SanityArrayItem<T> = T & {
  _key: string
}

/** @public */
declare type SanityDocumentValue<T extends {}> = T & {
  _type: string
  _id: string
  _rev?: string
  _updatedAt?: string
  _createdAt?: string
}

/** @public */
declare interface SanityReferenceValue {
  _type: 'reference'
  _ref: string
  _weak?: boolean
}

/** @public */
declare interface SanitySlugValue {
  _type: 'slug'
  current: string
}

/** @public */
declare interface SerializedAPICallSignature
  extends Omit<APICallSignature, 'parameters' | 'returnType' | 'typeParameters'> {
  parameters: SanityArrayItem<SerializedAPIParameter>[]
  returnType: SanityArrayItem<SerializedAPIToken>[]
  typeParameters: SanityArrayItem<SerializedAPITypeParameter>[]
}

/** @public */
declare interface SerializedAPIClass
  extends Omit<APIClass, 'export' | 'members' | 'package' | 'release' | 'typeParameters'> {
  export: SanityReferenceValue
  members: SanityArrayItem<SerializedAPIClassMember>[]
  package: SanityReferenceValue
  release: SanityReferenceValue
  typeParameters: SanityArrayItem<SerializedAPITypeParameter>[]
}

/** @public */
declare type SerializedAPIClassMember =
  | SerializedAPIConstructor
  | SerializedAPIPropertyMember
  | SerializedAPIMethodMember

/** @public */
declare interface SerializedAPIConstructor extends Omit<APIConstructor, 'parameters'> {
  parameters: SanityArrayItem<SerializedAPIParameter>[]
}

/** @public */
declare interface SerializedAPIConstructSignature
  extends Omit<APIConstructSignature, 'parameters' | 'returnType' | 'typeParameters'> {
  parameters: SanityArrayItem<SerializedAPIParameter>[]
  returnType: SanityArrayItem<SerializedAPIToken>[]
  typeParameters: SanityArrayItem<SerializedAPITypeParameter>[]
}

/** @public */
declare interface SerializedAPIEnum extends Omit<APIEnum, 'export' | 'package' | 'release'> {
  export: SanityReferenceValue
  package: SanityReferenceValue
  release: SanityReferenceValue
}

/** @public */
declare interface SerializedAPIExport
  extends Omit<APIExport, 'exports' | 'members' | 'package' | 'release'> {
  members: SanityArrayItem<SanityReferenceValue>[]
  package: SanityReferenceValue
  release: SanityReferenceValue
}

/** @public */
declare interface SerializedAPIFunction
  extends Omit<
    APIFunction,
    'export' | 'package' | 'parameters' | 'propsType' | 'release' | 'returnType' | 'typeParameters'
  > {
  export: SanityReferenceValue
  package: SanityReferenceValue
  parameters: SanityArrayItem<SerializedAPIParameter>[]
  propsType?: SanityReferenceValue
  release: SanityReferenceValue
  returnType: SanityArrayItem<SerializedAPIToken>[]
  typeParameters: SanityArrayItem<SerializedAPITypeParameter>[]
  /**
   * Used to store if the function is overloading another function
   */
  isOverloading: boolean
}

/** @public */
declare interface SerializedAPIIndexSignature
  extends Omit<APIIndexSignature, 'parameters' | 'returnType'> {
  parameters: SanityArrayItem<SerializedAPIParameter>[]
  returnType: SanityArrayItem<SerializedAPIToken>[]
}

/** @public */
declare interface SerializedAPIInterface
  extends Omit<
    APIInterface,
    'export' | 'extends' | 'members' | 'package' | 'release' | 'typeParameters'
  > {
  _type: 'api.interface'
  export: SanityReferenceValue
  extends: {
    _type: 'api.extend'
    type: SanityArrayItem<SerializedAPIToken>[]
  }[]
  members: SanityArrayItem<SerializedAPIInterfaceMember>[]
  package: SanityReferenceValue
  release: SanityReferenceValue
  typeParameters: SanityArrayItem<SerializedAPITypeParameter>[]
}

/** @public */
declare type SerializedAPIInterfaceMember =
  | SerializedAPICallSignature
  | SerializedAPIConstructSignature
  | SerializedAPIMethodSignature
  | SerializedAPIPropertySignature
  | SerializedAPIIndexSignature

/**
 * All API member types.
 *
 * @public
 */
declare type SerializedAPIMember =
  | SerializedAPIClass
  | SerializedAPIEnum
  | SerializedAPIFunction
  | SerializedAPIInterface
  | SerializedAPINamespace
  | SerializedAPITypeAlias
  | SerializedAPIVariable

/** @public */
declare interface SerializedAPIMethodMember
  extends Omit<APIMethod, 'parameters' | 'returnType' | 'typeParameters'> {
  parameters: SanityArrayItem<SerializedAPIParameter>[]
  returnType: SanityArrayItem<SerializedAPIToken>[]
  typeParameters: SanityArrayItem<SerializedAPITypeParameter>[]
}

/** @public */
declare interface SerializedAPIMethodSignature
  extends Omit<APIMethodSignature, 'parameters' | 'returnType' | 'typeParameters'> {
  parameters: SanityArrayItem<SerializedAPIParameter>[]
  returnType: SanityArrayItem<SerializedAPIToken>[]
  typeParameters: SanityArrayItem<SerializedAPITypeParameter>[]
}

/** @public */
declare interface SerializedAPINamespace
  extends Omit<APINamespace, 'export' | 'members' | 'package' | 'release'> {
  export: SanityReferenceValue
  members: SanityArrayItem<SerializedAPIMember>[]
  package: SanityReferenceValue
  release: SanityReferenceValue
}

/** @public */
declare interface SerializedAPIPackage extends Omit<APIPackage, 'latestRelease' | 'releases'> {
  latestRelease: SanityReferenceValue
  releases: SanityArrayItem<SanityReferenceValue>[]
}

/** @public */
declare interface SerializedAPIParameter extends Omit<APIParameter, 'type'> {
  type: SanityArrayItem<SerializedAPIToken>[]
}

/** @public */
declare interface SerializedAPIPropertyMember extends Omit<APIProperty, 'type'> {
  type: SanityArrayItem<SerializedAPIToken>[]
}

/** @public */
declare interface SerializedAPIPropertySignature extends Omit<APIPropertySignature, 'type'> {
  type: SanityArrayItem<SerializedAPIToken>[]
}

/** @public */
declare interface SerializedAPIRelease extends Omit<APIRelease, 'exports' | 'package'> {
  exports: SanityArrayItem<SanityReferenceValue>[]
  package: SanityReferenceValue
}

/** @public */
declare interface SerializedAPISymbol extends Omit<APISymbol, 'package'> {
  package: SanityReferenceValue
}

/** @public */
declare interface SerializedAPIToken extends Omit<APIToken, 'member'> {
  member?: SanityReferenceValue
}

/** @public */
declare interface SerializedAPITypeAlias
  extends Omit<APITypeAlias, 'export' | 'package' | 'release' | 'type' | 'typeParameters'> {
  export: SanityReferenceValue
  type: SanityArrayItem<SerializedAPIToken>[]
  package: SanityReferenceValue
  release: SanityReferenceValue
  typeParameters: SanityArrayItem<SerializedAPITypeParameter>[]
}

/** @public */
declare interface SerializedAPITypeParameter
  extends Omit<APITypeParameter, 'constraintType' | 'defaultType'> {
  constraintType?: SanityArrayItem<SerializedAPIToken>[]
  defaultType: SanityArrayItem<SerializedAPIToken>[]
}

/** @public */
declare interface SerializedAPIVariable
  extends Omit<APIVariable, 'export' | 'package' | 'propsType' | 'release' | 'type'> {
  export: SanityReferenceValue
  type: SanityArrayItem<SerializedAPIToken>[]
  package: SanityReferenceValue
  propsType?: SanityReferenceValue
  release: SanityReferenceValue
}

/** @public */
declare type TSDocAPIMember = APIMember & {versions: string[]}

/** @public */
declare type TSDocAPISymbol = APISymbol & {members: TSDocAPIMember[]}

/**
 * @example
 * ```tsx
 * import {TSDocApp, createTSDocMemoryStore} from '@sanity/tsdoc/react'
 * import {useState} from 'react'
 *
 * const store = createTSDocMemoryStore({docs: []})
 * const [path, setPath] = useState<string | null>(null)
 *
 * <TSDocApp path={path} onPathChange={setPath} store={store} />
 * ```
 *
 * @beta
 * */
export declare function TSDocApp(props: TSDocAppProps): React.ReactNode

/** @public */
declare interface TSDocAppParams {
  exportPath: string | null
  memberName?: string | null
  packageName: string | null
  packageScope: string | null
  releaseVersion: string | null
  memberSlug?: string | null
}

/** @beta */
export declare interface TSDocAppProps {
  basePath?: string
  onPathChange: (value: string, replace?: boolean) => void
  path: string
  store: TSDocStore
  releaseVersion?: string
}

/** @beta */
export declare function TSDocArticle(props: {
  data: APIMember & {
    versions: string[]
  }
}): React.ReactNode

/** @public */
declare interface TSDocComment {
  _type: 'tsdoc.docComment'
  customBlocks?: SanityArrayItem<TSDocCustomBlock>[]
  deprecated?: TSDocDeprecatedBlock
  exampleBlocks?: SanityArrayItem<TSDocExampleBlock>[]
  modifierTags?: SanityArrayItem<TSDocModifierTag>[]
  parameters?: SanityArrayItem<TSDocParamBlock>[]
  remarks?: TSDocRemarksBlock
  returns?: TSDocReturnsBlock
  seeBlocks?: SanityArrayItem<TSDocSeeBlock>[]
  summary?: SanityArrayItem<PortableTextNode>[]
}

/** @beta */
export declare interface TSDocContextValue {
  basePath: string
  path: string
  params: TSDocAppParams
  updateParams: (fn: (params: TSDocAppParams) => TSDocAppParams) => void
  onPathChange: (nextPath: string, replace?: boolean) => void
  store: TSDocStore
}

/** @public */
declare interface TSDocCustomBlock {
  _type: 'tsdoc.customBlock'
  content?: PortableTextNode[]
  tag: string
}

/** @public */
declare interface TSDocDeprecatedBlock {
  _type: 'tsdoc.deprecatedBlock'
  content?: PortableTextNode[]
}

/** @beta */
export declare function TSDocDetail(): React.ReactNode

/** @public */
declare interface TSDocExampleBlock {
  _type: 'tsdoc.exampleBlock'
  content?: PortableTextNode[]
}

/** @public */
declare interface TSDocExportData {
  isLatest: boolean
  name: string
  package: {name: string; scope: string | null}
  path: string
  release: {version: string}
  members: SanityArrayItem<APIMember>[]
}

/** @beta */
export declare function TSDocMemberTitle(props: {data: APIMember}): React.ReactNode

/** @public */
declare interface TSDocModifierTag {
  _type: 'tsdoc.modifierTag'
  name: string
}

/** @beta */
export declare function TSDocNav(props: {
  showVersionMenu?: boolean
  expandPackages?: boolean
  expandSubPackages?: boolean
}): React.ReactNode

/** @internal */
export declare interface TSDocNavExportData
  extends Omit<TSDocExportData, 'members'>,
    TSDocNavGroupedMembers {}

/** @internal */
export declare interface TSDocNavGroupedMembers {
  classes: APIClass[]
  enums: APIEnum[]
  functions: APIFunction[]
  interfaces: APIInterface[]
  namespaces: APINamespace[]
  reactComponents: (APIClass | APIFunction | APIVariable)[]
  reactHooks: APIFunction[]
  typeAliases: APITypeAlias[]
  variables: APIVariable[]
}

/** @public */
declare interface TSDocParamBlock {
  _type: 'tsdoc.paramBlock'
  content?: PortableTextNode[]
  name: string
}

/** @beta */
export declare function TSDocProvider(props: TSDocProviderProps): React.ReactNode

/** @beta */
export declare interface TSDocProviderProps {
  basePath?: string
  children: React.ReactNode
  onPathChange: (nextPath: string, replace?: boolean) => void
  params?: TSDocAppParams
  path: string
  store: TSDocStore
}

/** @public */
declare interface TSDocRemarksBlock {
  _type: 'tsdoc.remarksBlock'
  content?: PortableTextNode[]
}

/** @public */
declare interface TSDocReturnsBlock {
  _type: 'tsdoc.returnsBlock'
  content?: PortableTextNode[]
}

/** @beta */
export declare function TSDocSearch(): React.ReactNode

/** @public */
declare interface TSDocSeeBlock {
  _type: 'tsdoc.seeBlock'
  content?: PortableTextNode[]
}

/** @public */
declare interface TSDocStore {
  exports: {
    get: (params: {
      packageScope: string | null
      packageName: string
      releaseVersion: string
    }) => Promise<TSDocExportData[] | undefined>
  }

  member: {
    get: (params: TSDocAppParams) => Promise<TSDocAPIMember[] | null | undefined>
  }

  package: {
    get: (params: TSDocAppParams) => Promise<APIPackage | null | undefined>
  }

  packages: {
    get: () => Promise<APIPackage[] | null | undefined>
  }

  symbol: {
    get: (params: {
      name: string
      packageName: string
      packageScope: string | null
    }) => Promise<TSDocAPISymbol | null | undefined>
    search: (params: {
      query: string
      packageName: string
      packageScope: string | null
    }) => Promise<TSDocSymbolSearchResult[]>
  }
}

/** @beta */
export declare function TSDocSymbol(
  props: Omit<CardProps, 'as'> & {
    member?: APIMember
    fontSize?: number
    name: string
    packageScope?: string | null
    packageName?: string | null
    tooltip?: Omit<TooltipProps, 'content'>
  },
): React.ReactNode

/** @beta */
export declare function TSDocSymbolPreview(
  props: Omit<CardProps, 'as' | 'padding'> & {
    fontSize?: number
    member?: APIMember
    name: string
    packageName?: string
    packageScope?: string | null
  },
): React.ReactNode

/** @public */
declare type TSDocSymbolSearchResult = (APISymbol & {
  _id: string
  members: {exportPath: string; releaseVersion: string}[]
})[]

/** @beta */
export declare function useExports(): {
  data: TSDocExportData[] | null
  error: Error | null
  loading: boolean
}

/** @beta */
export declare function useMember(props: {params: TSDocAppParams | null}): {
  data?: TSDocAPIMember[] | null
  error: Error | null
  loading: boolean
}

/** @beta */
export declare function useMemberLink(props: {params: TSDocAppParams | null}): {
  href: string
  onClick: (event: MouseEvent_2 | KeyboardEvent) => void
}

/** @beta */
export declare function usePackage(props: {params: TSDocAppParams | null}): {
  data: APIPackage | null | undefined
  error: Error | null
  loading: boolean
}

/** @beta */
export declare function usePackages(): {
  data: APIPackage[] | null
  error: Error | null
  loading: boolean
}

/** @beta */
export declare function useSymbol(props: UseSymbolProps): {
  data?: UseSymbolData | null
  error: Error | null
  loading: boolean
}

/** @beta */
export declare interface UseSymbolData extends APISymbol {
  members: APIMember[]
}

/** @beta */
export declare interface UseSymbolProps {
  member?: APIMember
  name: string
  packageScope?: string | null
  packageName?: string | null
}

/** @beta */
export declare function useSymbolSearch(props: {query: string | null}): {
  data: (APISymbol & {
    _id: string
    members: {
      exportPath: string
      releaseVersion: string
    }[]
  })[]
  error: Error | null
  loading: boolean
}

/** @beta */
export declare function useTSDoc(): TSDocContextValue

export {}
