<template>
  <div ref="containerRef" class="markdown-renderer">
    <template v-for="segment in segments" :key="segment.key">
      <div
        v-if="segment.type === 'text'"
        class="markdown-text-segment"
        v-html="renderText(segment.content)"
      ></div>
      <CodeBlock
        v-else
        :content="segment.content"
        :language="segment.language"
        :is-streaming="!segment.closed"
      />
    </template>
  </div>
</template>

<script setup lang="ts">
import { computed, inject, nextTick, onMounted, onUpdated, ref, watch } from 'vue';
import CodeBlock from './CodeBlock.vue';
import {
  parseMarkdownSegments,
  renderMarkdownText,
  renderMathBlocks
} from '@/composables/useMarkdownRenderer';

defineOptions({ name: 'MarkdownRenderer' });

const props = defineProps<{
  content: string;
  isStreaming?: boolean;
}>();

const containerRef = ref<HTMLElement | null>(null);
const onMathRendered = inject<() => void>('mathRenderedCallback', () => {});

const segments = computed(() => parseMarkdownSegments(props.content || '', props.isStreaming));

function renderText(text: string) {
  return renderMarkdownText(text);
}

function renderMath() {
  nextTick(() => {
    if (containerRef.value) {
      renderMathBlocks(containerRef.value);
      onMathRendered();
    }
  });
}

onMounted(renderMath);
onUpdated(renderMath);
watch(() => props.content, renderMath, { immediate: true });
</script>

<style scoped>
.markdown-renderer {
  display: contents;
}

.markdown-text-segment {
  display: block;
}

.markdown-text-segment > *:first-child {
  margin-top: 0;
}

.markdown-text-segment > *:last-child {
  margin-bottom: 0;
}
</style>
