<script setup lang="ts">
import { ref, computed, watch, onBeforeUnmount } from 'vue'
import { storeToRefs } from 'pinia'
import { useEditor } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
import Link from '@tiptap/extension-link'
import Underline from '@tiptap/extension-underline'
import TextAlign from '@tiptap/extension-text-align'
import Placeholder from '@tiptap/extension-placeholder'
import { EntityObject } from '@MailManager/models/entity'
import type { CollectionObject, MessageAddressObject } from '@MailManager/models'
import { useMailStore } from '@/stores/mailStore'
import { useMailCompositionStore } from '@/stores/mailCompositionStore'
import { ComposerMode } from '@/types/composer'
import ComposerToolbar from '@/components/composer/ComposerToolbar.vue'
import ComposerSender from '@/components/composer/ComposerSender.vue'
import ComposerRecipients from '@/components/composer/ComposerRecipients.vue'
import ComposerAttachments from '@/components/composer/ComposerAttachments.vue'
import ComposerEditor from '@/components/composer/ComposerEditor.vue'

// Props
interface Props {
  mode: ComposerMode
  source?: EntityObject | MessageAddressObject | null
  folder?: CollectionObject | null
}

const props = defineProps<Props>()

// Emits
const emit = defineEmits<{
  close: []
}>()

const mailStore = useMailStore()
const compositionStore = useMailCompositionStore()
const {
  composerSending: sending,
} = storeToRefs(mailStore)

const {
  activeDraft,
  saving,
  stageStatus,
} = storeToRefs(compositionStore)

// State
const showCc = ref(false)
const showBcc = ref(false)
const applyingDraftToEditor = ref(false)

const sender = computed({
  get: () => activeDraft.value?.sender ?? null,
  set: value => {
    if (value) {
      compositionStore.updateSender(value)
    }
  },
})

const to = computed({
  get: () => activeDraft.value?.message.to ?? [],
  set: value => compositionStore.updateRecipients('to', value),
})

const cc = computed({
  get: () => activeDraft.value?.message.cc ?? [],
  set: value => compositionStore.updateRecipients('cc', value),
})

const bcc = computed({
  get: () => activeDraft.value?.message.bcc ?? [],
  set: value => compositionStore.updateRecipients('bcc', value),
})

const subject = computed({
  get: () => activeDraft.value?.message.subject ?? '',
  set: value => compositionStore.updateSubject(value),
})

const attachments = computed(() => activeDraft.value?.attachments ?? {})

// Initialize Tiptap editor
const editor = useEditor({
  extensions: [
    StarterKit,
    Link.configure({
      openOnClick: false,
    }),
    Underline,
    TextAlign.configure({
      types: ['heading', 'paragraph'],
    }),
    Placeholder.configure({
      placeholder: 'Write your message...',
    }),
  ],
  content: '',
  editorProps: {
    attributes: {
      class: 'tiptap-editor pa-4',
    },
  },
})

watch(
  [() => props.mode, () => props.source, () => editor.value],
  ([, , currentEditor]) => {
    if (!currentEditor) {
      return
    }

    compositionStore.openDraft(props.mode, props.source)
    showCc.value = (activeDraft.value?.message.cc.length ?? 0) > 0
    showBcc.value = (activeDraft.value?.message.bcc.length ?? 0) > 0

    applyingDraftToEditor.value = true
    currentEditor.commands.setContent(activeDraft.value?.message.body.html || '')
    applyingDraftToEditor.value = false
  },
  { immediate: true },
)

// Computed
const canSend = computed(() => {
  return to.value.length > 0 && subject.value.trim().length > 0
})

// Watch editor content changes
watch(editor, currentEditor => {
  if (!currentEditor) {
    return
  }

  const handleUpdate = () => {
    if (applyingDraftToEditor.value) {
      return
    }

    compositionStore.updateBody({
      html: currentEditor.getHTML(),
      text: currentEditor.getText(),
    })
  }

  currentEditor.on('update', handleUpdate)

  return () => {
    currentEditor.off('update', handleUpdate)
  }
})

// Cleanup
onBeforeUnmount(() => {
  void compositionStore.flushSave()
  editor.value?.destroy()
})

// Handlers
const handleClose = async () => {
  await compositionStore.closeDraft()
  emit('close')
}

const handleSend = async () => {
  await compositionStore.sendDraft()
}

const handleAttach = async (files: File[]) => {
  await compositionStore.addAttachments(files)
}

const handleDetach = async (identifier: string) => {
  await compositionStore.removeAttachment(identifier)
}

const toggleCc = () => {
  showCc.value = !showCc.value
}

const toggleBcc = () => {
  showBcc.value = !showBcc.value
}

// Toolbar actions
const toggleBold = () => editor.value?.chain().focus().toggleBold().run()
const toggleItalic = () => editor.value?.chain().focus().toggleItalic().run()
const toggleUnderline = () => editor.value?.chain().focus().toggleUnderline().run()
const toggleBulletList = () => editor.value?.chain().focus().toggleBulletList().run()
const toggleOrderedList = () => editor.value?.chain().focus().toggleOrderedList().run()
const setLink = () => {
  const url = window.prompt('Enter URL:')
  if (url) {
    editor.value?.chain().focus().setLink({ href: url }).run()
  }
}
const removeLink = () => editor.value?.chain().focus().unsetLink().run()
const toggleLink = () => {
  if (isActive('link')) {
    removeLink()
    return
  }

  setLink()
}
const isActive = (name: string, attrs?: any) => {
  return editor.value?.isActive(name, attrs) || false
}
</script>

<template>
  <div class="message-composer">
    <ComposerToolbar
      :mode="mode"
      :status="stageStatus"
      :can-send="canSend"
      :sending="sending"
      @close="handleClose"
      @send="handleSend"
    />

    <div class="composer-content">
      <ComposerSender
        v-model="sender"
        :options="compositionStore.senderIdentities"
      />

      <ComposerRecipients
        :to="to"
        :cc="cc"
        :bcc="bcc"
        :subject="subject"
        :show-cc="showCc"
        :show-bcc="showBcc"
        @update:to="to = $event"
        @update:cc="cc = $event"
        @update:bcc="bcc = $event"
        @update:subject="subject = $event"
        @toggle:cc="toggleCc"
        @toggle:bcc="toggleBcc"
      />

      <v-divider />

      <ComposerAttachments
        v-if="Object.keys(attachments).length > 0"
        :attachments="attachments"
        @remove="handleDetach"
      />

      <v-divider v-if="Object.keys(attachments).length > 0" />

      <ComposerEditor
        :editor="editor"
        :is-bold-active="isActive('bold')"
        :is-italic-active="isActive('italic')"
        :is-underline-active="isActive('underline')"
        :is-bullet-list-active="isActive('bulletList')"
        :is-ordered-list-active="isActive('orderedList')"
        :is-link-active="isActive('link')"
        @bold="toggleBold"
        @italic="toggleItalic"
        @underline="toggleUnderline"
        @bullet-list="toggleBulletList"
        @ordered-list="toggleOrderedList"
        @link="toggleLink"
        @attach="handleAttach"
      />
    </div>
  </div>
</template>

<style scoped lang="scss">
.message-composer {
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.composer-toolbar {
  flex-shrink: 0;
  border-bottom: 1px solid rgb(var(--v-border-color));
}

.composer-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

</style>
