<script setup lang="ts">
import { computed, nextTick, ref, useTemplateRef, watchEffect } from 'vue'
import 'katex/dist/katex.min.css'
import { throttle, debounce } from 'lodash-es'
// import 'highlight.js/styles/panda-syntax-light.css'
import 'highlight.js/styles/atom-one-dark.min.css'
import './style/github-markdown.css'
import { copyToClip } from '@/utils/copy'
import { useI18n } from 'vue-i18n'
import { createMarkedInst } from './utils/markdown-parser'

interface Props {
  rawTextContent: string
  fontSize?: number | string
  color?: string
  darkTheme?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  rawTextContent: '',
  fontSize: '14px',
  color: '#333',
  darkTheme: true,
})

const markdownRenderContainerRef = useTemplateRef<HTMLDivElement>('markdownRenderContainerRef')
const { t } = useI18n()

const markedInst = createMarkedInst()
let btnEventController = new AbortController()

const renderTextContent = ref('')

const articleContainerStyle = computed(() => {
  return {
    fontSize: props.fontSize,
    color: props.color,
  }
})

const textContentParser = throttle(
  (text: string) => {
    ;(markedInst.parse(text) as Promise<string>).then((res) => {
      renderTextContent.value = res
    })
  },
  500,
  { leading: true, trailing: true },
)

const codeCopyBtnEventBind = debounce(
  () => {
    if (markdownRenderContainerRef.value) {
      const codeCopyBtnElList = markdownRenderContainerRef.value.getElementsByClassName('code-copy-btn')
      const foldBtnElList = markdownRenderContainerRef.value.getElementsByClassName('fold-btn')

      btnEventController.abort()
      btnEventController = new AbortController()

      /* 遍历 */
      ;[...codeCopyBtnElList].forEach((elItem) => {
        elItem.addEventListener(
          'click',
          () => {
            const code = elItem.parentElement?.parentElement?.nextElementSibling?.firstChild?.firstChild?.textContent

            if (code) {
              copyToClip(code).then(() => {
                window.$message.success(t('common_module.copy_success_message'))
              })
            }
          },
          { signal: btnEventController.signal },
        )
      })

      /* 遍历 */
      ;[...foldBtnElList].forEach((elItem) => {
        elItem.addEventListener(
          'click',
          () => {
            elItem && elItem.classList.toggle('folding')

            const codeRenderWrapperEl = elItem.parentElement?.parentElement?.nextElementSibling

            if (codeRenderWrapperEl) {
              codeRenderWrapperEl?.classList.toggle('folding')
            }
          },
          { signal: btnEventController.signal },
        )
      })
    }
  },
  1000,
  { leading: false, trailing: true },
)

watchEffect(() => {
  textContentParser(props.rawTextContent)

  nextTick(() => {
    setTimeout(() => {
      codeCopyBtnEventBind()
    }, 60)
  })
})

function getRenderTextContent() {
  return renderTextContent.value
}

defineExpose({
  getRenderTextContent,
})
</script>

<template>
  <div ref="markdownRenderContainerRef" class="markdown-render-container">
    <article
      class="markdown-body markdown-render-inner"
      :data-theme="darkTheme ? 'dark' : 'light'"
      :style="articleContainerStyle"
      v-html="renderTextContent"
    />
  </div>
</template>

<style lang="scss" scoped>
@include custom-scrollbar(6px);

.markdown-render-container {
  .markdown-render-inner {
    overflow-x: auto;
    font-family: 'Microsoft YaHei UI';
    word-break: break-all;
    background-color: unset;

    & > :deep(pre) {
      padding: 0;
    }
  }

  :deep(.code-render-container) {
    font-family: 'Microsoft YaHei UI';
    font-size: v-bind('props.fontSize');

    .code-operation-bar-container {
      display: flex;
      justify-content: space-between;
      padding: 8px 16px;
      color: v-bind('props.darkTheme ? "#fff" : "#333"');
      user-select: none;
      background-color: v-bind('props.darkTheme ? "#323740" : "#EEEEEE"');

      // background-color: v-bind('props.darkTheme ? "#484a4b" : "#EEEEEE"');
      // background-color: v-bind('props.darkTheme ? "#333842" : "#EEEEEE"');

      .language {
        display: flex;
        align-items: center;
        justify-content: center;
      }

      .fold-btn {
        display: inline-block;
        margin-left: 16px;
        transition: transform ease-in-out 0.2s !important;
        transform: rotate(270deg);

        &.folding {
          transform: rotate(90deg);
        }
      }

      .code-copy-btn,
      .fold-btn {
        font-size: 14px;
        cursor: pointer;
        transition: color ease-in-out 0.3s;

        &:hover {
          color: #777ef9;
        }
      }
    }

    .code-render-inner {
      padding: 10px 16px;
      margin: 0;
      overflow-x: auto;
    }

    .code-render-wrapper {
      height: fit-content;
      transition: all 0.3s linear;

      &.folding {
        height: 0;
        overflow: hidden;
      }
    }
  }
}

:deep(.markdown-body) {
  &[data-theme='dark'] {
    /* stylelint-disable-next-line custom-property-pattern */
    --bgColor-muted: #282c34;
  }

  &[data-theme='light'] {
    /* stylelint-disable-next-line custom-property-pattern */
    --bgColor-muted: #fdfdfd;
  }

  & .code-container-wrapper {
    display: inline-flex;
    flex-direction: column;
    width: 100%;
  }
}

:deep(pre) {
  &::-webkit-scrollbar {
    width: 6px;
    height: 6px;
  }

  &::-webkit-scrollbar-corner {
    background: transparent;
  }

  &::-webkit-scrollbar-thumb {
    background: #bfbfbf;
    border-radius: 5px;
  }

  &::-webkit-scrollbar-track {
    background: transparent;
    border-radius: 2px;
  }
}

:deep(.mermaid) {
  background-color: #fff;

  .mermaid-viewer {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    max-width: 100%;
    height: 300px;
    overflow: hidden;
    background-image: radial-gradient(circle, #e4e4e48c 2px, #0000 0);
    background-size: 30px 30px;
    border-radius: 12px;

    svg {
      display: block;
      max-width: 100% !important;
    }
  }
}

:deep(.mermaid-error) {
  display: flex;
  gap: 5px;
  align-items: center;
  justify-content: center;
  padding: 20px 10px;
  font-family: 'Microsoft YaHei UI';
  font-size: 14px;
  color: #999;

  .render-error-icon-container {
    width: 20px;
    height: 20px;
    background-image: url('@/assets/svgs/mermaid-error.svg');
    background-size: 100% 100%;
  }
}

:deep(.mermaid-rendering-container) {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-width: 200px;
  height: 300px;
  background-color: #fff;

  .mermaid-rendering-content {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: #999;
    background-image: radial-gradient(circle, #e4e4e48c 2px, #0000 0);
    background-size: 30px 30px;
  }
}
</style>
