<script setup lang="ts">
import mermaid from 'mermaid';
import { computed, onMounted, ref, watch } from 'vue';

const props = defineProps<{
  chart: string;
}>();

const container = ref<HTMLElement | null>(null);
const error = ref('');

let initialized = false;
let diagramId = 0;

function initMermaid() {
  if (initialized) {
    return;
  }

  mermaid.initialize({
    startOnLoad: false,
    theme: 'neutral',
    securityLevel: 'loose',
    fontFamily: 'Inter, Arial, sans-serif',
    flowchart: {
      useMaxWidth: true,
      htmlLabels: true,
    },
  });

  initialized = true;
}

const source = computed(() => props.chart.trim());

async function renderDiagram() {
  if (!import.meta.client || !container.value) {
    return;
  }

  try {
    initMermaid();
    error.value = '';
    diagramId += 1;
    container.value.removeAttribute('data-processed');
    container.value.id = `mermaid-diagram-${diagramId}`;
    container.value.textContent = source.value;
    await mermaid.run({
      nodes: [container.value],
    });
  } catch (cause) {
    error.value = cause instanceof Error ? cause.message : 'Failed to render Mermaid diagram.';
  }
}

onMounted(() => {
  void renderDiagram();
});

watch(source, () => {
  void renderDiagram();
});
</script>

<template>
  <div class="mermaid-diagram">
    <div v-if="error" class="mermaid-diagram__error">{{ error }}</div>
    <pre v-else ref="container" class="mermaid-diagram__canvas mermaid" />
  </div>
</template>

<style scoped>
.mermaid-diagram {
  margin: 1.25rem 0 1.75rem;
  border: 1px solid #d9dee7;
  border-radius: 20px;
  background: #fff;
  overflow: hidden;
}

.mermaid-diagram__canvas {
  padding: 1rem;
  margin: 0;
  white-space: pre-wrap;
}

.mermaid-diagram__canvas :deep(svg) {
  display: block;
  width: 100%;
  height: auto;
}

.mermaid-diagram__error {
  padding: 1rem 1.25rem;
  color: #b42318;
  background: #fef3f2;
  font-size: 0.95rem;
}
</style>
