<script setup lang="ts">
import CKEditor from '@/ckeditor/CKEditor'
import BalloonEditor from '@ckeditor/ckeditor5-editor-balloon/src/ballooneditor'
import EssentialsPlugin from '@ckeditor/ckeditor5-essentials/src/essentials'
import BoldPlugin from '@ckeditor/ckeditor5-basic-styles/src/bold'
import ItalicPlugin from '@ckeditor/ckeditor5-basic-styles/src/italic'
import UnderlinePlugin from '@ckeditor/ckeditor5-basic-styles/src/underline'
import StrikethroughPlugin from '@ckeditor/ckeditor5-basic-styles/src/strikethrough'
import LinkPlugin from '@ckeditor/ckeditor5-link/src/link'
import HeadingPlugin from '@ckeditor/ckeditor5-heading/src/heading'
import ParagraphPlugin from '@ckeditor/ckeditor5-paragraph/src/paragraph'
import ListPlugin from '@ckeditor/ckeditor5-list/src/list'
import AutoformatPlugin from '@ckeditor/ckeditor5-autoformat/src/autoformat'
import ContextedPlugin from '@/ckeditor/ContextedPlugin'
import { mdToHtml, htmlToMd } from '@/utils/markdown'
import { getNoteByTitle, setActiveNote, addNote } from '@/composables/useNotes'
import Autocomplete from '@/components/Note/Autocomplete.vue'

const props = defineProps<{ note: Note }>()

const emit = defineEmits<{
  update: [mdText: string]
}>()

const html = mdToHtml(props.note.content)

const editor = BalloonEditor
const editorData = ref<string>(html)
const editorConfig = {
  plugins: [
    EssentialsPlugin,
    BoldPlugin,
    ItalicPlugin,
    UnderlinePlugin,
    StrikethroughPlugin,
    LinkPlugin,
    HeadingPlugin,
    ParagraphPlugin,
    ListPlugin,
    AutoformatPlugin,
    ContextedPlugin,
  ],
  toolbar: {
    items: [
      'bold',
      'italic',
      'underline',
      'strikethrough',
      'link',
      'undo',
      'redo',
      'heading',
      'bulletedList',
      'numberedList',
    ],
  },
  placeholder: 'Click here to start typing...',
}

const editorElement = ref<HTMLInputElement | null>(null)
watch(editorData, () => emit('update', htmlToMd(editorData.value)))
let editorInstance: any

const handleClick = ({ data }: { data: any }) => {
  if (!data.domTarget.hasAttribute('data-contexted-link')) return
  const noteTitle = data.domTarget.textContent as string
  let note: BaseNote | Note | undefined = getNoteByTitle(noteTitle)
  if (!note) note = addNote(noteTitle, '')
  setActiveNote(note.id)
}

const autocompleteRef = ref<InstanceType<typeof Autocomplete> | null>(null)
const showAutocomplete = ref(false)
const autocompleteStyle = ref({})
const autocompleteText = ref('')
const autocompleteReverse = ref(false)

const handleAutocomplete = async (event: AutocompleteEvent) => {
  const position = event.position
  if (position && editorElement.value) {
    const rect: any = editorElement.value?.getBoundingClientRect()
    const lineHeight = parseFloat(
      window.getComputedStyle(event.domElement || editorElement.value).lineHeight
    )
    autocompleteStyle.value = {
      top: `${position.top - rect.top + lineHeight}px`,
      left: `${position.left - rect.left}px`,
    }
  }
  autocompleteText.value = event.autocompleteText || ''
  showAutocomplete.value = event.show
  await nextTick()
  const autocompleteElem = autocompleteRef.value?.$el
  const autocompleteRect = autocompleteRef.value?.$el.getBoundingClientRect()
  const editorRect = editorElement.value?.getBoundingClientRect()
  if (
    autocompleteElem &&
    autocompleteRect &&
    editorRect &&
    autocompleteRect.bottom > editorRect.bottom
  ) {
    const autocompleteHeight = parseFloat(
      window.getComputedStyle(autocompleteElem).height
    )
    autocompleteStyle.value = {
      ...autocompleteStyle.value,
      top: `${position.top - editorRect.top - autocompleteHeight}px`,
    }
    autocompleteReverse.value = true
  } else {
    autocompleteReverse.value = false
  }
}

const handleContextedKeypress = (event: any) => {
  if (autocompleteRef.value) autocompleteRef.value.handleKeypress(event)
}

const createLink = (link: string) => {
  if (!editor) return
  const model = editorInstance.model
  const getPosition = () => model.document.selection.anchor
  // const getNodes = () => {
  //   const nodes = [
  //     getPosition().nodeBefore,
  //     getPosition().nodeAfter,
  //     getPosition().textNnode,
  //   ]
  //   return nodes.map((node) => ({
  //     data: node?.data,
  //     attrs: Array.from(node?.getAttributes() || []),
  //   }))
  // }
  // console.log(getNodes())
  let nodeToRemove: any
  if (getPosition().nodeBefore?.hasAttribute('autocomplete')) {
    // Insert new link
    nodeToRemove = getPosition().nodeBefore
  } else if (getPosition().nodeBefore?.hasAttribute('contextedLink')) {
    // Update existing link from end of existing link (backspace)
    nodeToRemove = getPosition().nodeBefore
  } else if (getPosition().textNode?.hasAttribute('contextedLink')) {
    // Update existing link from middle of existing link
    nodeToRemove = getPosition().textNode
  } else if (getPosition().nodeAfter?.hasAttribute('contextedLink')) {
    // Update existing link from beginning (delete)
    nodeToRemove = getPosition().nodeAfter
  }

  model.change((writer: any) => {
    if (nodeToRemove) writer.remove(nodeToRemove)
    writer.insertText(link, { contextedLink: true }, getPosition(), 'after')
    model.enqueueChange((writer: any) => {
      const nodeAfter = getPosition().nodeAfter
      if (!nodeAfter || (nodeAfter && !nodeAfter.data.startsWith(']]'))) {
        writer.insertText(']]', model.document.selection.getFirstPosition())
      }
    })
    showAutocomplete.value = false
  })
}
</script>
<template>
  <div class="relative" ref="editorElement">
    <CKEditor
      class="w-full flex-grow text-[110%] font-light"
      :editor="editor"
      v-model="editorData"
      :config="editorConfig"
      @editor-ready="(editor) => (editorInstance = editor)"
      @click="handleClick"
      @contexted-link-autocomplete="handleAutocomplete"
      @contexted-keypress="handleContextedKeypress"
    ></CKEditor>
    <Autocomplete
      v-if="showAutocomplete"
      ref="autocompleteRef"
      :autocomplete-text="autocompleteText"
      :style="autocompleteStyle"
      @create-link="createLink"
      class="absolute w-[250px]"
      :class="autocompleteReverse && 'flex-col-reverse'"
    />
  </div>
</template>
<style>
.ck-content {
  padding: 0 !important;
  border: 0 !important;
  outline: none !important;
  box-shadow: none !important;
}
.ck-content a[data-contexted-link='true'] {
  @apply cursor-pointer font-semibold text-primary hover:bg-gray-200;
}
</style>
