<script setup lang="ts">
import 'highlight.js/styles/magula.min.css';
import MarkdownIt from 'markdown-it';
import hljs from 'highlight.js';
import { nextTick, onMounted, onUnmounted, ref } from 'vue';
import { useRoute } from 'vue-router';

import mditFigureWithPCaption from 'markdown-it-image-figures';
import mditMedia from 'markdown-it-html5-media';
import mditAnchor from 'markdown-it-anchor';
import mditHighlight from 'markdown-it-highlightjs';
import { initLang, initTheme } from 'src/utils/ui';
import { baseUrl } from 'src/stores/utils';

import { useManualStore } from 'src/stores/manual';

const ROUTE = useRoute();
const manualStore = useManualStore();

const md = new MarkdownIt()
  .use(mditAnchor)
  .use(mditMedia.html5Media)
  .use(mditHighlight, { hljs })
  .use(mditFigureWithPCaption, { figcaption: 'alt' });

const wrapper = ref<HTMLDivElement>();
const category = ref('');
const page = ref('');
const content = ref('');
const contentParsed = ref<ReturnType<typeof md.parse>>();
const contentViewing = ref('');
const toc = ref(true);

onMounted(async () => {
  if (typeof ROUTE.params['category'] === 'string') {
    category.value = ROUTE.params['category'];
  }

  if (typeof ROUTE.params['page'] === 'string') {
    page.value = ROUTE.params['page'];
  }

  initLang();
  initTheme();

  await getContent();

  window.addEventListener('scroll', onScroll);
  window.addEventListener('resize', onResize);
});

onUnmounted(() => {
  window.removeEventListener('scroll', onScroll);
  window.removeEventListener('resize', onResize);
});

async function getContent() {
  if (!category.value || !page.value) return;

  if (ROUTE.name === 'ManualView') {
    const res = await manualStore.getManualByPage({
      category: category.value,
      pageName: page.value,
    });
    if (res && res.ok) {
      const text = await res.text();
      content.value = text;
      contentParsed.value = md.parse(text, {});
    }
  }
  if (ROUTE.name === 'TroubleshootingView') {
    const res = await manualStore.getTroubleshootingByPage({
      category: category.value,
      pageName: page.value,
    });
    if (res && res.ok) {
      const text = await res.text();
      content.value = text;
      contentParsed.value = md.parse(text, {});
    }
  }
}

function onScroll() {
  let current = '';
  document.querySelectorAll<HTMLElement>('h2,h3').forEach((v) => {
    if (
      window.top &&
      window.top.scrollY + window.innerHeight / 2 > v.offsetTop
    ) {
      current = v.id;
    }
  });
  contentViewing.value = current;
}

function onResize() {
  if (window.innerWidth > 1024) {
    toc.value = true;
  }
}

async function scrollTo(id: string) {
  const pos = document.getElementById(id)?.offsetTop;
  await nextTick(() => {
    if (window.innerWidth < 1024) toc.value = false;
  });
  if (pos) {
    wrapper.value?.scrollTo({
      top: pos,
      behavior: 'smooth',
    });
  }
}
</script>

<template>
  <main
    class="full-height q-gutter-sm no-wrap"
    :class="{ column: !toc && $q.screen.lt.md, 'row reverse': $q.screen.gt.sm }"
  >
    <section
      v-if="toc"
      class="surface-1 rounded col-md-3 col-12 scroll full-height"
    >
      <q-list padding>
        <template v-for="(token, idx) in contentParsed" :key="idx">
          <q-item
            v-if="token.tag === 'h2' && token.type === 'heading_open'"
            class="tabNative"
            active-class="text-blue-7 active-item text-weight-medium tabActive"
            :active="contentViewing === token.attrGet('id')"
            @click="scrollTo(token.attrGet('id') || '')"
            clickable
            v-ripple
            dense
            exact
          >
            <q-item-section>
              <q-item-label>
                <q-icon size="11px" name="mdi-circle-medium" />
                <span class="q-pl-xs">
                  {{ contentParsed?.[idx + 1].content }}
                </span>
              </q-item-label>
            </q-item-section>
          </q-item>
          <q-item
            v-if="token.tag === 'h3' && token.type === 'heading_open'"
            class="tabNative child-tab"
            active-class="text-blue-7 active-item text-weight-medium tabActive"
            :active="contentViewing === token.attrGet('id')"
            @click="scrollTo(token.attrGet('id') || '')"
            clickable
            v-ripple
            dense
            exact
          >
            <q-item-section>
              <q-item-label>
                <span class="q-pl-xl">
                  {{ contentParsed?.[idx + 1].content }}
                </span>
              </q-item-label>
            </q-item-section>
          </q-item>
        </template>
      </q-list>
    </section>

    <section v-if="!toc && $q.screen.lt.md">
      <q-btn
        dense
        class="full-width text-capitalize"
        flat
        @click="toc = true"
        color="info"
      >
        {{ $t('general.tableOfContent') }}
      </q-btn>
    </section>

    <section
      v-if="$q.screen.gt.xs || (!toc && $q.screen.xs)"
      ref="wrapper"
      class="markdown col scroll full-height rounded"
    >
      <div
        style="
          width: 100%;
          flex: 1;
          border-radius: 0.5rem;
          border: 1px solid var(--border-color);
          padding: 1rem;
        "
        class="surface-1"
        v-html="
          md.render(
            content.replaceAll(
              'assets/',
              $route.name === 'ManualView'
                ? `${baseUrl}/manual/${category}/assets/`
                : `${baseUrl}/troubleshooting/${category}/assets/`,
            ),
          )
        "
      ></div>
    </section>
  </main>
</template>

<style lang="css" scoped>
.toc {
  top: 4rem;
}

.active {
  color: red;
}

.markdown :deep(:where(h1, h2, h3, h4, h5, h6)) {
  line-height: 1.5;
  padding-block: 1rem !important;
}

.markdown {
  counter-set: h1 0;
  counter-reset: h1;
}

.markdown :deep(h1) {
  counter-reset: h2;
}

.markdown :deep(h2) {
  counter-reset: h3;
}

.markdown :deep(h3) {
  counter-reset: h4;
}

.markdown :deep(h2:before) {
  counter-increment: h2;
  content: counter(h2) '. ';
}

.markdown :deep(h3:before) {
  counter-increment: h3;
  content: counter(h2) '.' counter(h3) ' ';
}

.markdown :deep(h4:before) {
  counter-increment: h4;
  content: counter(h2) '.' counter(h3) '.' counter(h4) ' ';
}

.markdown :deep(blockquote) {
  background-color: var(--surface-2);
  border-radius: 8px;
  padding: 8px;
  margin-bottom: 1rem;
}

.markdown :deep(blockquote > p:last-child) {
  margin-bottom: 0;
}

.markdown :deep(img) {
  vertical-align: middle;
}

.markdown :deep(p img) {
  padding-inline: 0.25rem;
}

.markdown :deep(figure) {
  margin: 0;
  text-align: center;
  padding: 1rem;
  width: 100%;
}

.markdown :deep(figure img) {
  max-width: 90%;
}

.markdown :deep(p:has(img:only-child) img) {
  max-width: 100%;
}

.markdown :deep(h1) {
  text-align: left;
  margin-top: -1rem;
  margin-inline: -1rem;
  font-size: 24px;
  font-weight: 700;
  background-color: var(--surface-2);
  border-radius: 8px 8px 0px 0px;
  padding: 0px 16px;
}

.markdown :deep(.hljs) {
  border-radius: 8px;
}

.markdown :deep(a) {
  color: hsla(var(--info-bg));
}

.markdown :deep(figcaption) {
  text-align: center;
}

.markdown :deep(h2) {
  text-align: left;
  margin-block: 0;
  font-size: 18px;
  font-weight: 600;
  padding: 0px 16px;
}

.markdown :deep(h3) {
  text-align: left;
  margin-block: 0;
  font-size: 16px;
  font-weight: 600;
  padding: 0px 16px;
}

.markdown :deep(h4) {
  text-align: left;
  margin-block: 0;
  font-size: 16px;
  font-weight: 600;
  padding: 0px 16px;
}

.markdown :deep(video) {
  width: 100%;
}

.markdown :deep(table) {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 1.5rem;
}

.markdown :deep(:where(table th)) {
  background: var(--surface-2);
  border: 1px solid var(--border-color);
}

.markdown :deep(:where(table td, table th)) {
  border: 1px solid var(--border-color);
  padding: 0.25rem 1rem;
}
</style>
