import type { MarkdownChartPluginOptions } from '@vuepress/plugin-markdown-chart'
import type { MarkdownHintPluginOptions } from '@vuepress/plugin-markdown-hint'
import type { MarkdownImagePluginOptions } from '@vuepress/plugin-markdown-image'
import type { MarkdownIncludePluginOptions } from '@vuepress/plugin-markdown-include'
import type { MarkdownMathPluginOptions } from '@vuepress/plugin-markdown-math'
import type { PluginConfig } from 'vuepress'
import type { MarkdownPowerPluginOptions } from 'vuepress-plugin-md-power'
import type { MarkdownOptions, ThemeBuiltinPlugins } from '../../shared/index.js'
import { isPlainObject } from '@vuepress/helper'
import { markdownChartPlugin } from '@vuepress/plugin-markdown-chart'
import { markdownHintPlugin } from '@vuepress/plugin-markdown-hint'
import { markdownImagePlugin } from '@vuepress/plugin-markdown-image'
import { markdownIncludePlugin } from '@vuepress/plugin-markdown-include'
import { markdownMathPlugin } from '@vuepress/plugin-markdown-math'
import { markdownPowerPlugin } from 'vuepress-plugin-md-power'
import { MARKDOWN_CHART_FIELDS, MARKDOWN_POWER_FIELDS } from '../detector/index.js'
import { getThemeConfig } from '../loadConfig/index.js'

export function markdownPlugins(pluginOptions: ThemeBuiltinPlugins): PluginConfig {
  const options = getThemeConfig()
  const plugins: PluginConfig = []
  let { hint, image, include, math, mdChart, mdPower } = splitMarkdownOptions(options.markdown ?? {})

  plugins.push(markdownHintPlugin({
    hint: hint.hint ?? true,
    alert: hint.alert ?? true,
    injectStyles: false,
  }))

  if (pluginOptions.markdownPower !== false) {
    const shikiOptions = options.codeHighlighter ?? pluginOptions.shiki

    const shikiTheme = shikiOptions && 'theme' in shikiOptions
      ? shikiOptions.theme
      : shikiOptions && 'themes' in shikiOptions
        ? shikiOptions.themes
        : { light: 'vitesse-light', dark: 'vitesse-dark' }

    const repl = mdPower?.repl ?? pluginOptions.markdownPower?.repl
    plugins.push(markdownPowerPlugin({
      fileTree: true,
      plot: true,
      icons: true,
      ...pluginOptions.markdownPower || {},
      ...mdPower,
      repl: repl ? { theme: shikiTheme as any, ...repl } : repl,
    }))
  }

  mdChart ??= pluginOptions.markdownChart
  if (mdChart) {
    plugins.push(markdownChartPlugin(mdChart))
  }

  math ??= pluginOptions.markdownMath
  if (math !== false) {
    plugins.push(markdownMathPlugin(math ?? { type: 'katex' }))
  }

  image ??= pluginOptions.markdownImage
  if (image) {
    plugins.push(markdownImagePlugin(image))
  }

  include ??= pluginOptions.markdownInclude
  if (include !== false) {
    plugins.push(markdownIncludePlugin(isPlainObject(include) ? include : {}))
  }

  return plugins
}

function splitMarkdownOptions(options: MarkdownOptions): {
  mdPower: MarkdownPowerPluginOptions
  mdChart?: false | MarkdownChartPluginOptions
  image?: false | MarkdownImagePluginOptions
  include?: boolean | MarkdownIncludePluginOptions
  math?: false | MarkdownMathPluginOptions
  hint: MarkdownHintPluginOptions
} {
  const { hint, alert, oldDemo, image, include, math, ...restOptions } = options
  const mdChart: MarkdownChartPluginOptions = {}
  const mdPower: MarkdownPowerPluginOptions = {}

  for (const key in restOptions) {
    if (MARKDOWN_CHART_FIELDS.includes(key as keyof MarkdownChartPluginOptions)) {
      mdChart[key] = restOptions[key]
    }
    else if (MARKDOWN_POWER_FIELDS.includes(key as keyof MarkdownPowerPluginOptions)) {
      mdPower[key] = restOptions[key]
    }
  }

  const mdChartKeys = Object.keys(mdChart)

  return {
    hint: { hint, alert },
    image,
    include,
    math,
    mdChart: mdChartKeys.length && mdChartKeys.some(key => mdChart[key] !== false) ? mdChart : false,
    mdPower,
  }
}
