import type { Ref, UnwrapNestedRefs } from 'vue'
import type { OARequest } from '../lib/codeSamples/request'
import type { OperationSlot, ParsedOperation } from '../types'
import vitesseDark from '@shikijs/themes/vitesse-dark'
import vitesseLight from '@shikijs/themes/vitesse-light'
import { useDark } from '@vueuse/core'
import { ref } from 'vue'
import { generateCodeSample } from '../lib/codeSamples/generateCodeSample'
import { deepUnref } from '../lib/deepUnref'
import { locales } from '../locales'

export interface ThemeConfig {
  highlighterTheme: {
    light: any
    dark: any
  }
}

export interface PathConfig {
  showBaseURL: Ref<boolean>
}

export interface RequestConfig {
  defaultView: Ref<'schema' | 'contentType' | 'autogenerated'>
}

export interface JsonViewerConfig {
  deep: Ref<number>
  renderer: Ref<'vue-json-pretty' | 'shiki' | string>
}

export interface SchemaViewerConfig {
  deep: Ref<number>
}

export interface HeadingLevels {
  h1: number
  h2: number
  h3: number
  h4: number
  h5: number
  h6: number
}

export interface ResponseConfig {
  responseCodeSelector: Ref<'tabs' | 'select'>
  maxTabs: Ref<number>
  body: {
    defaultView: Ref<'schema' | 'contentType' | 'autogenerated'>
  }
}

type PlaygroundJsonEditorMode = 'text' | 'tree' | 'table'

export interface PlaygroundConfig {
  jsonEditor: {
    mode: Ref<PlaygroundJsonEditorMode>
    mainMenuBar: Ref<boolean>
    navigationBar: Ref<boolean>
  }
}

export interface SecurityConfig {
  defaultScheme: Ref<string | null>
}

type OperationBadges = 'deprecated' | 'operationId'

export interface OperationConfig {
  badges?: Ref<OperationBadges[]>
  slots?: Ref<OperationSlot[]>
  /** @deprecated Use server.getServers instead */
  getServers?: GetServersFunction | null
  hiddenSlots?: Ref<OperationSlot[]>
  cols?: Ref<1 | 2>
  defaultBaseUrl?: string
}

export type Languages = 'es' | 'en' | 'ja' | 'pt-BR' | string

export type Messages = Record<Languages, Record<string, string>>

export interface AvailableLocale {
  code: string
  label: string
}

export interface I18nConfig {
  locale: Ref<Languages>
  fallbackLocale: Ref<Languages>
  messages: Messages
  availableLocales?: AvailableLocale[]
}

export interface SpecConfig {
  groupByTags?: Ref<boolean>
  collapsePaths?: Ref<boolean>
  showPathsSummary?: Ref<boolean>
  avoidCirculars?: Ref<boolean>
  lazyRendering?: Ref<boolean>
  defaultTag?: string
  defaultTagDescription?: string
  wrapExamples?: boolean
}

export interface ServerConfig {
  allowCustomServer: boolean
  getServers: GetServersFunction | null
}

export interface UseThemeConfig {
  theme?: Partial<ThemeConfig>
  path?: Partial<PathConfig>
  requestBody?: Partial<RequestConfig>
  jsonViewer?: Partial<JsonViewerConfig>
  schemaViewer?: Partial<SchemaViewerConfig>
  headingLevels?: Partial<HeadingLevels>
  response?: Partial<ResponseConfig>
  playground?: Partial<PlaygroundConfig>
  security?: Partial<SecurityConfig>
  operation?: Partial<OperationConfig>
  i18n?: Partial<I18nConfig>
  spec?: Partial<SpecConfig>
  codeSamples?: Partial<CodeSamplesConfig>
  linksPrefixes?: Partial<LinksPrefixesConfig>
  server?: Partial<ServerConfig>
}

export interface CodeSamplesConfig {
  langs: string[]
  defaultLang: string
  availableLanguages: LanguageConfig[]
  generator: GeneratorFunction
  defaultHeaders: Record<string, string>
}

export interface LinksPrefixesConfig {
  tags: string
  operations: string
}

interface LanguageConfig {
  lang: string
  label: string
  highlighter: string
  icon?: string
}

export type PartialUseThemeConfig = Partial<UnwrapNestedRefs<UseThemeConfig>>

type GeneratorFunction = (lang: string, request: OARequest) => Promise<string>

type GetServersFunction = ({ method, path, operation }: { method: string, path: string, operation: ParsedOperation }) => string[] | null

export const DEFAULT_OPERATION_SLOTS: OperationSlot[] = [
  'header',
  'path',
  'description',
  'security',
  'parameters',
  'request-body',
  'responses',
  'playground',
  'code-samples',
  'branding',
  'footer',
]

export const DEFAULT_BASE_URL = 'http://localhost'

export const availableLanguages: LanguageConfig[] = [
  {
    lang: 'curl',
    label: 'cURL',
    highlighter: 'bash',
    icon: 'curl',
  },
  {
    lang: 'javascript',
    label: 'JavaScript',
    highlighter: 'javascript',
    icon: '.js',
  },
  {
    lang: 'php',
    label: 'PHP',
    highlighter: 'php',
    icon: '.php',
  },
  {
    lang: 'python',
    label: 'Python',
    highlighter: 'python',
    icon: '.py',
  },
]

const themeConfig: UseThemeConfig = {
  theme: {
    highlighterTheme: {
      light: vitesseLight,
      dark: vitesseDark,
    },
  },
  path: {
    showBaseURL: ref<boolean>(false),
  },
  requestBody: {
    defaultView: ref<'schema' | 'contentType' | 'autogenerated'>('contentType'),
  },
  jsonViewer: {
    deep: ref<number>(Number.POSITIVE_INFINITY),
    renderer: ref<'vue-json-pretty' | 'shiki' | string>('vue-json-pretty'),
  },
  schemaViewer: {
    deep: ref<number>(Number.POSITIVE_INFINITY),
  },
  headingLevels: {
    h1: 1,
    h2: 2,
    h3: 3,
    h4: 4,
    h5: 5,
    h6: 6,
  },
  response: {
    responseCodeSelector: ref<'tabs' | 'select'>('tabs'),
    maxTabs: ref<number>(5),
    body: {
      defaultView: ref<'schema' | 'contentType' | 'autogenerated'>('contentType'),
    },
  },
  playground: {
    jsonEditor: {
      mode: ref<PlaygroundJsonEditorMode>('tree'),
      mainMenuBar: ref<boolean>(false),
      navigationBar: ref<boolean>(false),
    },
  },
  security: {
    defaultScheme: ref<string | null>(null),
  },
  operation: {
    badges: ref<OperationBadges[]>(['deprecated']),
    slots: ref(DEFAULT_OPERATION_SLOTS),
    hiddenSlots: ref([]),
    cols: ref(2),
    defaultBaseUrl: DEFAULT_BASE_URL,
    getServers: null,
  },
  i18n: {
    locale: ref<Languages>('en'),
    fallbackLocale: ref<Languages>('en'),
    messages: locales,
    availableLocales: [
      {
        code: 'en',
        label: 'English',
      },
      {
        code: 'es',
        label: 'Español',
      },
      {
        code: 'ja',
        label: 'Japanese',
      },
      {
        code: 'pt-BR',
        label: 'Português (Brasil)',
      },
    ],
  },
  spec: {
    groupByTags: ref(true),
    collapsePaths: ref(false),
    showPathsSummary: ref(true),
    avoidCirculars: ref(false),
    lazyRendering: ref(false),
    defaultTag: 'Default',
    defaultTagDescription: '',
    wrapExamples: true,
  },
  codeSamples: {
    langs: [
      'curl',
      'javascript',
      'php',
      'python',
    ],
    defaultLang: 'curl',
    availableLanguages,
    generator: (lang: string, request: OARequest) => generateCodeSample(lang, request),
    defaultHeaders: {},
  },
  linksPrefixes: {
    tags: '/tags/',
    operations: '/operations/',
  },
  server: {
    allowCustomServer: false,
    getServers: null,
  },
}

const defaultThemeConfig: UnwrapNestedRefs<UseThemeConfig> = { ...deepUnref(themeConfig) } as PartialUseThemeConfig

const isDark = useDark({
  storageKey: 'vitepress-theme-appearance',
})

export function useTheme(initialConfig: PartialUseThemeConfig = {}) {
  setConfig(initialConfig)

  function setConfig(config: PartialUseThemeConfig) {
    if (!config || !Object.keys(config).length) {
      return
    }

    if (config?.theme?.highlighterTheme) {
      setHighlighterTheme(config.theme.highlighterTheme)
    }

    if (config?.requestBody?.defaultView !== undefined) {
      setRequestBodyDefaultView(config.requestBody.defaultView)
    }

    if (config?.path?.showBaseURL !== undefined) {
      setShowBaseURL(config.path.showBaseURL)
    }

    if (config?.jsonViewer?.deep !== undefined) {
      setJsonViewerDeep(config.jsonViewer.deep)
    }

    if (config?.jsonViewer?.renderer !== undefined) {
      setJsonViewerRenderer(config.jsonViewer.renderer)
    }

    if (config?.schemaViewer?.deep !== undefined) {
      setSchemaViewerDeep(config.schemaViewer.deep)
    }

    if (config?.headingLevels !== undefined) {
      setHeadingLevels(config.headingLevels)
    }

    if (config?.response?.responseCodeSelector !== undefined) {
      setResponseCodeSelector(config.response.responseCodeSelector)
    }

    if (config?.response?.maxTabs !== undefined) {
      setResponseCodeMaxTabs(config.response.maxTabs)
    }

    if (config?.response?.body?.defaultView !== undefined) {
      setResponseBodyDefaultView(config.response.body.defaultView)
    }

    if (config?.playground?.jsonEditor?.mode !== undefined) {
      setPlaygroundJsonEditorMode(config.playground.jsonEditor.mode)
    }

    if (config?.playground?.jsonEditor?.mainMenuBar !== undefined) {
      setPlaygroundJsonEditorMainMenuBar(config.playground.jsonEditor.mainMenuBar)
    }

    if (config?.playground?.jsonEditor?.navigationBar !== undefined) {
      setPlaygroundJsonEditorNavigationBar(config.playground.jsonEditor.navigationBar)
    }

    if (config?.security?.defaultScheme !== undefined) {
      setSecurityDefaultScheme(config.security.defaultScheme)
    }

    if (config?.operation?.badges !== undefined) {
      setOperationBadges(config.operation.badges)
    }

    if (config?.operation?.slots !== undefined) {
      setOperationSlots(config.operation.slots)
    }

    if (config?.operation?.hiddenSlots !== undefined) {
      setOperationHiddenSlots(config.operation.hiddenSlots)
    }

    if (config?.operation?.cols !== undefined) {
      setOperationCols(config.operation.cols)
    }

    if (config?.operation?.defaultBaseUrl !== undefined) {
      setOperationDefaultBaseUrl(config.operation.defaultBaseUrl)
    }

    if (config?.operation?.getServers !== undefined) {
      setOperationServers(config.operation.getServers)
    }

    if (config?.i18n !== undefined) {
      setI18nConfig(config.i18n)
    }

    if (config?.spec !== undefined) {
      setSpecConfig(config.spec)
    }

    if (config?.codeSamples !== undefined) {
      setCodeSamplesConfig(config.codeSamples)
    }

    if (config?.linksPrefixes !== undefined) {
      setLinksPrefixesConfig(config.linksPrefixes)
    }

    if (config?.server !== undefined) {
      setServerConfig(config.server)
    }
  }

  function reset() {
    setConfig(defaultThemeConfig)
  }

  function getState() {
    return deepUnref(themeConfig)
  }

  function getLocale(): Languages {
    return themeConfig?.i18n?.locale?.value || 'en'
  }

  /**
   * @deprecated Use `setI18nConfig({ locale: value })` instead.
   */
  function setLocale(value: Languages) {
    console.warn('`setLocale` is deprecated. Use `setI18nConfig({ locale: value })` instead.')
    // @ts-expect-error: This is a valid expression.
    themeConfig.i18n.locale.value = value
  }

  function getHighlighterTheme() {
    return themeConfig?.theme?.highlighterTheme
  }

  function setHighlighterTheme(value: ThemeConfig['highlighterTheme']) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.theme.highlighterTheme = {
      ...themeConfig?.theme?.highlighterTheme,
      ...value,
    }
  }

  function getRequestBodyDefaultView(): 'schema' | 'contentType' | 'autogenerated' | undefined {
    return themeConfig?.requestBody?.defaultView?.value
  }

  function setRequestBodyDefaultView(value: 'schema' | 'contentType' | 'autogenerated') {
    // @ts-expect-error: This is a valid expression.
    themeConfig.requestBody.defaultView.value = value
  }

  function getShowBaseURL(): boolean | undefined {
    return themeConfig?.path?.showBaseURL?.value
  }

  function setShowBaseURL(value: boolean) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.path.showBaseURL.value = value
  }

  function getJsonViewerDeep(): number | undefined {
    return themeConfig?.jsonViewer?.deep?.value
  }

  function setJsonViewerDeep(value: number) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.jsonViewer.deep.value = value
  }

  function getJsonViewerRenderer(): 'vue-json-pretty' | 'shiki' | string {
    return themeConfig?.jsonViewer?.renderer?.value || 'vue-json-pretty'
  }

  function setJsonViewerRenderer(value: 'vue-json-pretty' | 'shiki' | string) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.jsonViewer.renderer.value = value
  }

  function getSchemaViewerDeep(): number | undefined {
    return themeConfig?.schemaViewer?.deep?.value
  }

  function setSchemaViewerDeep(value: number) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.schemaViewer.deep.value = value
  }

  function getHeadingLevels() {
    return themeConfig.headingLevels
  }

  function getHeadingLevel(level: keyof HeadingLevels): `h${1 | 2 | 3 | 4 | 5 | 6}` {
    if (!themeConfig.headingLevels) {
      return `h${level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
    }

    const headingLevel = themeConfig.headingLevels[level] as number

    if (headingLevel < 1 || headingLevel > 6) {
      throw new Error(`Heading level for ${level} must be between 1 and 6.`)
    }

    return `h${headingLevel}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
  }

  function setHeadingLevels(levels: Partial<UnwrapNestedRefs<HeadingLevels>>) {
    if (!themeConfig.headingLevels) {
      themeConfig.headingLevels = { }
    }

    for (const key of Object.keys(levels)) {
      const value = levels[key as keyof HeadingLevels] as number

      if (value < 1 || value > 6) {
        throw new Error(`Heading level for ${key} must be between 1 and 6.`)
      }
    }

    Object.assign(themeConfig.headingLevels, levels)
  }

  function getResponseCodeSelector(): 'tabs' | 'select' | undefined {
    return themeConfig?.response?.responseCodeSelector?.value
  }

  function setResponseCodeSelector(value: 'tabs' | 'select') {
    // @ts-expect-error: This is a valid expression.
    themeConfig.response.responseCodeSelector.value = value
  }

  function getResponseCodeMaxTabs(): number | undefined {
    return themeConfig?.response?.maxTabs?.value
  }

  function setResponseCodeMaxTabs(value: number) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.response.maxTabs.value = value
  }

  function getResponseBodyDefaultView(): 'schema' | 'contentType' | 'autogenerated' | undefined {
    return themeConfig?.response?.body?.defaultView?.value
  }

  function setResponseBodyDefaultView(value: 'schema' | 'contentType' | 'autogenerated') {
    // @ts-expect-error: This is a valid expression.
    themeConfig.response.body.defaultView.value = value
  }

  function getPlaygroundJsonEditorMode(): PlaygroundJsonEditorMode | undefined {
    return themeConfig?.playground?.jsonEditor?.mode.value
  }

  function setPlaygroundJsonEditorMode(value: PlaygroundJsonEditorMode) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.playground.jsonEditor.mode.value = value
  }

  function getPlaygroundJsonEditorMainMenuBar(): boolean | undefined {
    return themeConfig?.playground?.jsonEditor?.mainMenuBar?.value
  }

  function setPlaygroundJsonEditorMainMenuBar(value: boolean) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.playground.jsonEditor.mainMenuBar.value = value
  }

  function getPlaygroundJsonEditorNavigationBar(): boolean | undefined {
    return themeConfig?.playground?.jsonEditor?.navigationBar.value
  }

  function setPlaygroundJsonEditorNavigationBar(value: boolean) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.playground.jsonEditor.navigationBar.value = value
  }

  function getSecurityDefaultScheme(): string | null | undefined {
    return themeConfig?.security?.defaultScheme?.value
  }

  function setSecurityDefaultScheme(value: string | null) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.security.defaultScheme.value = value
  }

  function getOperationBadges(): OperationBadges[] {
    return [...(themeConfig?.operation?.badges?.value || [])]
  }

  function setOperationBadges(value: OperationBadges[]) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.operation.badges.value = value
  }

  function getOperationSlots(): OperationSlot[] | undefined {
    return themeConfig?.operation?.slots?.value
  }

  function setOperationSlots(value: OperationSlot[]) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.operation.slots.value = value
  }

  function getOperationHiddenSlots(): OperationSlot[] | undefined {
    return themeConfig?.operation?.hiddenSlots?.value
  }

  function setOperationHiddenSlots(value: OperationSlot[]) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.operation.hiddenSlots.value = value
  }

  function getOperationCols(): 1 | 2 | undefined {
    return themeConfig?.operation?.cols?.value
  }

  function setOperationCols(value: number) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.operation.cols.value = value
  }

  function getOperationDefaultBaseUrl(): string {
    return themeConfig?.operation?.defaultBaseUrl || DEFAULT_BASE_URL
  }

  function setOperationDefaultBaseUrl(value: string) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.operation.defaultBaseUrl = value
  }

  function getOperationServers(): GetServersFunction | null {
    if (themeConfig?.operation?.getServers) {
      console.warn('operation.getServers is deprecated. Use server.getServers instead.')
      return themeConfig.operation.getServers
    }

    return themeConfig?.server?.getServers || null
  }

  function setOperationServers(value: GetServersFunction | null) {
    // @ts-expect-error: This is a valid expression.
    themeConfig.operation.getServers = value
  }

  function getI18nConfig(): I18nConfig {
    return themeConfig.i18n as I18nConfig
  }

  function setI18nConfig(config: Partial<UnwrapNestedRefs<I18nConfig>>) {
    if (config.locale) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.i18n.locale.value = config.locale
    }

    if (config.fallbackLocale) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.i18n.fallbackLocale.value = config.fallbackLocale
    }

    if (config.messages) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.i18n.messages = config.messages
    }

    if (config.availableLocales) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.i18n.availableLocales = config.availableLocales
    }
  }

  function getSpecConfig() {
    return themeConfig.spec
  }

  function getWrapExamples() {
    return themeConfig?.spec?.wrapExamples
  }

  function setSpecConfig(config: Partial<UnwrapNestedRefs<SpecConfig>>) {
    if (!themeConfig.spec) {
      themeConfig.spec = {}
    }

    if (config.groupByTags !== undefined) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.spec.groupByTags.value = config.groupByTags
    }

    if (config.collapsePaths !== undefined) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.spec.collapsePaths.value = config.collapsePaths
    }

    if (config.showPathsSummary !== undefined) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.spec.showPathsSummary.value = config.showPathsSummary
    }

    if (config.avoidCirculars !== undefined) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.spec.avoidCirculars.value = config.avoidCirculars
    }

    if (config.lazyRendering !== undefined) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.spec.lazyRendering.value = config.lazyRendering
    }

    if (config.defaultTag !== undefined) {
      themeConfig.spec.defaultTag = config.defaultTag
    }

    if (config.defaultTagDescription !== undefined) {
      themeConfig.spec.defaultTagDescription = config.defaultTagDescription
    }

    if (config.wrapExamples !== undefined) {
      themeConfig.spec.wrapExamples = config.wrapExamples
    }
  }

  function getCodeSamplesLangs() {
    return themeConfig?.codeSamples?.langs?.filter((lang, index, self) => self.indexOf(lang) === index)
  }

  function getCodeSamplesDefaultLang() {
    const availableLangs = getCodeSamplesLangs() || []

    const defaultLang = themeConfig?.codeSamples?.defaultLang

    if (defaultLang && availableLangs.includes(defaultLang)) {
      return defaultLang
    }

    return availableLangs[0]
  }

  function getCodeSamplesAvailableLanguages() {
    return themeConfig?.codeSamples?.availableLanguages
  }

  function getCodeSamplesGenerator() {
    return themeConfig?.codeSamples?.generator
  }

  function getCodeSamplesDefaultHeaders() {
    return themeConfig?.codeSamples?.defaultHeaders
  }

  function setCodeSamplesConfig(config: Partial<UnwrapNestedRefs<CodeSamplesConfig>>) {
    if (config.langs) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.codeSamples.langs = config.langs.filter((lang, index, self) => self.indexOf(lang) === index)
    }

    if (config.defaultLang) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.codeSamples.defaultLang = config.defaultLang
    }

    if (config.availableLanguages) {
      setCodeSamplesAvailableLanguages(config.availableLanguages)
    }

    if (config.generator) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.codeSamples.generator = config.generator
    }

    if (config.defaultHeaders) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.codeSamples.defaultHeaders = config.defaultHeaders
    }
  }

  function setCodeSamplesAvailableLanguages(languages: LanguageConfig[]) {
    if (!themeConfig.codeSamples) {
      return
    }

    const uniqueLanguages = [...new Set(languages.map(({ lang }) => lang))]

    themeConfig.codeSamples.availableLanguages = uniqueLanguages.map((lang) => {
      const language
        = languages.find(l => l.lang === lang)
          ?? availableLanguages.find(l => l.lang === lang)

      return language || { lang, label: lang, highlighter: 'plaintext' }
    })
  }

  function getLinksPrefixesConfig() {
    return themeConfig.linksPrefixes
  }

  function setLinksPrefixesConfig(config: Partial<UnwrapNestedRefs<LinksPrefixesConfig>>) {
    if (config.tags) {
      (themeConfig.linksPrefixes as LinksPrefixesConfig).tags = config.tags
    }

    if (config.operations) {
      (themeConfig.linksPrefixes as LinksPrefixesConfig).operations = config.operations
    }
  }

  function getTagsLinkPrefix() {
    return themeConfig?.linksPrefixes?.tags
  }

  function getOperationsLinkPrefix() {
    return themeConfig?.linksPrefixes?.operations
  }

  function getServerConfig(): ServerConfig {
    return themeConfig.server as ServerConfig
  }

  function setServerConfig(config: Partial<UnwrapNestedRefs<ServerConfig>>) {
    if (config.allowCustomServer !== undefined) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.server.allowCustomServer = config.allowCustomServer
    }
    if (config.getServers !== undefined) {
      // @ts-expect-error: This is a valid expression.
      themeConfig.server.getServers = config.getServers
    }
  }

  function getServerAllowCustomServer(): boolean {
    return themeConfig.server?.allowCustomServer || false
  }

  return {
    isDark,
    schemaConfig: themeConfig.requestBody,
    reset,
    getState,
    getLocale,
    setLocale,
    getHighlighterTheme,
    /** @deprecated Use `getRequestBodyDefaultView` instead. */
    getSchemaDefaultView: getRequestBodyDefaultView,
    getRequestBodyDefaultView,
    /** @deprecated Use `setRequestBodyDefaultView` instead. */
    setSchemaDefaultView: setRequestBodyDefaultView,
    setRequestBodyDefaultView,
    getShowBaseURL,
    setShowBaseURL,
    getJsonViewerDeep,
    setJsonViewerDeep,
    getJsonViewerRenderer,
    setJsonViewerRenderer,
    getSchemaViewerDeep,
    setSchemaViewerDeep,
    getHeadingLevels,
    getHeadingLevel,
    setHeadingLevels,
    getResponseCodeSelector,
    setResponseCodeSelector,
    getResponseCodeMaxTabs,
    setResponseCodeMaxTabs,
    getResponseBodyDefaultView,
    setResponseBodyDefaultView,
    getPlaygroundJsonEditorMode,
    setPlaygroundJsonEditorMode,
    getPlaygroundJsonEditorMainMenuBar,
    setPlaygroundJsonEditorMainMenuBar,
    getPlaygroundJsonEditorNavigationBar,
    setPlaygroundJsonEditorNavigationBar,
    getSecurityDefaultScheme,
    setSecurityDefaultScheme,
    getOperationBadges,
    setOperationBadges,
    getOperationSlots,
    setOperationSlots,
    getOperationHiddenSlots,
    setOperationHiddenSlots,
    getOperationCols,
    setOperationCols,
    getOperationDefaultBaseUrl,
    getOperationServers,
    getI18nConfig,
    setI18nConfig,
    getSpecConfig,
    getWrapExamples,
    setSpecConfig,
    getCodeSamplesLangs,
    getCodeSamplesDefaultLang,
    getCodeSamplesAvailableLanguages,
    getCodeSamplesGenerator,
    getCodeSamplesDefaultHeaders,
    setCodeSamplesConfig,
    getLinksPrefixesConfig,
    setLinksPrefixesConfig,
    getTagsLinkPrefix,
    getOperationsLinkPrefix,
    getServerConfig,
    setServerConfig,
    getServerAllowCustomServer,
  }
}
