<style>
.editor
{
    white-space: pre-line;
    overflow: auto;
    outline: none;
    box-shadow: none !important;
}
</style>

<template>
  <div class="editor" contenteditable>
    <template
      v-if="model && model.length > 0">
      <MarkdownRenderer
        v-if="node"
        :key="key"
        :node="node"
        :proses="{
          'a': LiveA,
          'h1': LiveH1,
          'h2': LiveH2,
          'h3': LiveH3,
          'h4': LiveH4,
          'h5': LiveH5,
          'h6': LiveH6,
          'blockquote': LiveBlockquote,
        }"
      ></MarkdownRenderer>
    </template>
  </div>
</template>

<script setup lang="ts">
import LiveA from "~/components/prose/live/LiveA.vue";
import LiveH1 from "~/components/prose/live/LiveH1.vue";
import LiveH2 from "~/components/prose/live/LiveH2.vue";
import LiveH3 from "~/components/prose/live/LiveH3.vue";
import LiveH4 from "~/components/prose/live/LiveH4.vue";
import LiveH5 from "~/components/prose/live/LiveH5.vue";
import LiveH6 from "~/components/prose/live/LiveH6.vue";
import LiveBlockquote from "~/components/prose/ProseBlockquote.vue";

import { hash } from 'ohash'
import { watch, computed } from 'vue'
import type { Root, Node } from 'hast';
import { diffLines as diff } from 'diff';

const model = defineModel<string>();

const parser = useMarkdown();
const key = computed(() => hash(model.value));

const node = ref<Root>(), changes = ref();

watch(model, update);
update(model.value, "");

async function update(value: string | undefined, old: string | undefined) {
  if(value && old)
  {
    if(node.value)
    {
      const differences = diff(old, value, {
        newlineIsToken: true,
      });

      let removeStart = 0, removeEnd = 0; //Character count
      let addStart = 0, addEnd = 0; //Character count

      const needAdd = differences.find(e => e.added) !== undefined;
      const needRemove = differences.find(e => e.removed) !== undefined;

      for(const difference of differences)
      {
        if(!difference.added && !difference.removed)
        {
          removeStart += difference.value.length;
          addStart += difference.value.length;
        }
        else if(difference.added)
        {
          addEnd = addStart + difference.value.length;
        }
        else if(difference.removed)
        {
          removeEnd = removeStart + difference.value.length;
        }

        if((!needAdd || addEnd !== 0) && (!needRemove || removeEnd !== 0))
          break;
      }

      const oldNodes = getNodes(node.value.children, removeStart - 1, removeEnd + 1);
      let newNodes;

      if(oldNodes.length === 0)
      {
        node.value = parser(value);
      }
      else
      {
        const newStart = oldNodes[0].position?.start.offset;
        const newEnd = oldNodes[oldNodes.length - 1].position?.end.offset;

        const lengthDiff = value.length - old.length;

        newNodes = parser(value.substring(newStart ?? 0, (newEnd ?? 0) + lengthDiff));

        const root = node.value;
        //root.position?.end.offset

        node.value = parser(value);
      }
      console.log(node.value);
    }
    else
    {
      node.value = parser(value);
    }
  }
  else if(value)
  {
    node.value = parser(value);
  }
}
function getNodes(nodes: Node[], start: number, end: number)
{
  return nodes.filter(e => (e.position?.start.offset ?? 0) <= end && (e.position?.end.offset ?? 0) >= start);
}
</script>