<template>
  <div class="rich-editor-field">
    <span :id="labelId" class="rich-editor-label">{{ label }}</span>
    <div class="rich-editor-shell">
      <div class="rich-editor-toolbar">
        <div class="rich-editor-group" aria-label="Textstil">
          <button type="button" class="rich-editor-tool" title="Fett" aria-label="Fett" @mousedown.prevent @click="runCommand('bold')">
            <Bold class="h-4 w-4" />
          </button>
          <button type="button" class="rich-editor-tool" title="Kursiv" aria-label="Kursiv" @mousedown.prevent @click="runCommand('italic')">
            <Italic class="h-4 w-4" />
          </button>
          <button type="button" class="rich-editor-tool" title="Unterstreichen" aria-label="Unterstreichen" @mousedown.prevent @click="runCommand('underline')">
            <Underline class="h-4 w-4" />
          </button>
        </div>
        <div class="rich-editor-group" aria-label="Ausrichtung">
          <button type="button" class="rich-editor-tool" title="Linksbündig" aria-label="Linksbündig" @mousedown.prevent @click="runCommand('justifyLeft')">
            <AlignLeft class="h-4 w-4" />
          </button>
          <button type="button" class="rich-editor-tool" title="Zentrieren" aria-label="Zentrieren" @mousedown.prevent @click="runCommand('justifyCenter')">
            <AlignCenter class="h-4 w-4" />
          </button>
          <button type="button" class="rich-editor-tool" title="Rechtsbündig" aria-label="Rechtsbündig" @mousedown.prevent @click="runCommand('justifyRight')">
            <AlignRight class="h-4 w-4" />
          </button>
        </div>
        <div class="rich-editor-group" aria-label="Listen und Formatierung">
          <button type="button" class="rich-editor-tool" title="Aufzählung" aria-label="Aufzählung" @mousedown.prevent @click="runCommand('insertUnorderedList')">
            <List class="h-4 w-4" />
          </button>
          <button type="button" class="rich-editor-tool" title="Nummerierte Liste" aria-label="Nummerierte Liste" @mousedown.prevent @click="runCommand('insertOrderedList')">
            <ListOrdered class="h-4 w-4" />
          </button>
          <button type="button" class="rich-editor-tool" title="Formatierung entfernen" aria-label="Formatierung entfernen" @mousedown.prevent @click="runCommand('removeFormat')">
            <Eraser class="h-4 w-4" />
          </button>
        </div>
        <label class="rich-editor-select rich-editor-select--font">
          <span class="rich-editor-select-label">
            <Type class="h-4 w-4" />
            Schrift
          </span>
          <NativeSelect
            v-model="selectedFont"
            class="rich-editor-native-select"
            :options="fontOptions.map((font) => ({ label: font, value: font }))"
            @change="applyFont"
          />
        </label>
        <label class="rich-editor-select rich-editor-select--size">
          <span class="rich-editor-select-label">Größe</span>
          <NativeSelect
            v-model="selectedSize"
            class="rich-editor-native-select"
            :options="sizeOptions"
            @change="applySize"
          />
        </label>
      </div>
      <div
        ref="editorRef"
        class="rich-editor w-full text-sm leading-7 text-slate-700 outline-none"
        :class="[minHeightClass, { 'rich-editor--empty': editorEmpty }]"
        contenteditable="true"
        role="textbox"
        :aria-labelledby="labelId"
        :data-placeholder="placeholder"
        @blur="handleEditorBlur"
        @focus="isFocused = true"
        @input="updateModelFromEditor"
        @keyup="saveSelection"
        @mouseup="saveSelection"
        @paste="handlePaste"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  AlignCenter,
  AlignLeft,
  AlignRight,
  Bold,
  Eraser,
  Italic,
  List,
  ListOrdered,
  Type,
  Underline,
} from '@lucide/vue'
import { computed, nextTick, onMounted, ref, watch } from 'vue'

import { privacyContentToHtml, sanitizePrivacyHtml, stripPrivacyHtml } from '../../lib/privacyContent'
import NativeSelect from '../ui/NativeSelect.vue'

const props = withDefaults(defineProps<{
  modelValue: string
  label: string
  placeholder: string
  minHeightClass?: string
}>(), {
  minHeightClass: 'min-h-[320px]',
})

const emit = defineEmits<{
  'update:modelValue': [value: string]
}>()

const editorRef = ref<HTMLElement | null>(null)
const isFocused = ref(false)
const selectedFont = ref('Outfit')
const selectedSize = ref('3')
const labelId = `rich-editor-label-${Math.random().toString(36).slice(2)}`
let savedSelection: Range | null = null

const fontOptions = ['Outfit', 'Inter', 'Arial', 'Georgia', 'Times New Roman', 'Verdana']
const sizeOptions = [
  { value: '2', label: '13 px' },
  { value: '3', label: '15 px' },
  { value: '4', label: '18 px' },
  { value: '5', label: '22 px' },
]

const editorEmpty = computed(() => !stripPrivacyHtml(props.modelValue))

watch(
  () => props.modelValue,
  (content) => {
    if (!isFocused.value) {
      syncEditorContent(content)
    }
  },
)

onMounted(() => syncEditorContent(props.modelValue))

function syncEditorContent(content: string) {
  const editor = editorRef.value
  if (!editor) {
    return
  }

  const html = privacyContentToHtml(content)
  if (editor.innerHTML !== html) {
    editor.innerHTML = html
  }
}

function updateModelFromEditor() {
  const editor = editorRef.value
  if (!editor) {
    return
  }

  saveSelection()
  emit('update:modelValue', sanitizePrivacyHtml(editor.innerHTML))
}

function saveSelection() {
  const editor = editorRef.value
  const selection = window.getSelection()
  if (!editor || !selection?.rangeCount) {
    return
  }

  const range = selection.getRangeAt(0)
  const selectionInsideEditor = editor.contains(range.commonAncestorContainer)
    || editor === range.commonAncestorContainer
  if (selectionInsideEditor) {
    savedSelection = range.cloneRange()
  }
}

function restoreSelection() {
  const editor = editorRef.value
  const selection = window.getSelection()
  if (!editor || !selection || !savedSelection) {
    return
  }

  const selectionInsideEditor = editor.contains(savedSelection.commonAncestorContainer)
    || editor === savedSelection.commonAncestorContainer
  if (!selectionInsideEditor) {
    return
  }

  selection.removeAllRanges()
  selection.addRange(savedSelection)
}

function handleEditorBlur() {
  saveSelection()
  isFocused.value = false
}

async function focusEditor() {
  await nextTick()
  editorRef.value?.focus()
  restoreSelection()
}

async function runCommand(command: string, value?: string) {
  await focusEditor()
  document.execCommand(command, false, value)
  updateModelFromEditor()
}

function applyFont() {
  return runCommand('fontName', selectedFont.value)
}

function applySize() {
  return runCommand('fontSize', selectedSize.value)
}

function handlePaste(event: ClipboardEvent) {
  event.preventDefault()
  const html = event.clipboardData?.getData('text/html')
  const text = event.clipboardData?.getData('text/plain') ?? ''
  const safeHtml = html ? sanitizePrivacyHtml(html) : privacyContentToHtml(text)
  document.execCommand('insertHTML', false, safeHtml)
  updateModelFromEditor()
}
</script>

<style scoped>
.rich-editor-field {
  display: grid;
  gap: 14px;
}

.rich-editor-label {
  display: block;
  padding-left: 2px;
  color: #64748b;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.18em;
  line-height: 1.2;
  text-transform: uppercase;
}

.rich-editor-shell {
  overflow: hidden;
  border: 1px solid #ddd6fe;
  border-radius: 28px;
  background: #fcfbff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.82), 0 18px 48px rgba(139, 108, 219, 0.08);
  transition: border-color 180ms ease, box-shadow 180ms ease;
}

.rich-editor-shell:focus-within {
  border-color: #9b7ce4;
  box-shadow: 0 0 0 4px rgba(139, 108, 219, 0.12), 0 18px 48px rgba(139, 108, 219, 0.12);
}

.rich-editor-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 10px;
  padding: 18px;
  border-bottom: 1px solid #ede9fe;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.96) 0%, rgba(250, 247, 255, 0.88) 100%);
}

.rich-editor-group,
.rich-editor-select {
  min-height: 52px;
  border: 1px solid #e4def8;
  border-radius: 18px;
  background: #fff;
  box-shadow: 0 8px 22px rgba(139, 108, 219, 0.08);
}

.rich-editor-group {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 7px;
}

.rich-editor-tool {
  display: grid;
  height: 36px;
  width: 36px;
  place-items: center;
  border: 1px solid transparent;
  border-radius: 13px;
  background: transparent;
  color: #6d5a86;
  cursor: pointer;
  transition:
    background-color 160ms ease,
    border-color 160ms ease,
    box-shadow 160ms ease,
    color 160ms ease,
    transform 160ms ease;
}

.rich-editor-tool:hover,
.rich-editor-tool:focus-visible {
  border-color: #d8c9fb;
  background: #f4edff;
  color: #7c3aed;
  transform: translateY(-1px);
  box-shadow: 0 8px 18px rgba(139, 108, 219, 0.14);
}

.rich-editor-tool:active {
  transform: translateY(0);
  box-shadow: none;
}

.rich-editor-tool:focus-visible {
  outline: none;
}

.rich-editor-select {
  display: grid;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px 10px;
}

.rich-editor-select--font {
  max-width: 260px;
}

.rich-editor-select--size {
  max-width: 170px;
}

.rich-editor-select-label {
  display: flex;
  align-items: center;
  gap: 7px;
  color: #64748b;
  font-size: 0.68rem;
  font-weight: 850;
  letter-spacing: 0.16em;
  line-height: 1;
  text-transform: uppercase;
}

.rich-editor-select-label svg {
  color: #8b5cf6;
}

.rich-editor-native-select :deep(.native-select__trigger) {
  min-height: 42px;
  padding: 6px 7px 6px 12px;
  border-radius: 15px;
  font-size: 0.9rem;
}

.rich-editor-native-select :deep(.native-select__chevron) {
  width: 30px;
  height: 30px;
  border-radius: 12px;
}

.rich-editor {
  padding: 24px 26px 28px;
  background: #fcfbff;
}

.rich-editor :deep(p) {
  margin: 0 0 0.85rem;
}

.rich-editor :deep(ul),
.rich-editor :deep(ol) {
  margin: 0 0 0.85rem 1.25rem;
  padding-left: 1rem;
}

.rich-editor :deep(li) {
  margin: 0.2rem 0;
}

.rich-editor--empty::before {
  content: attr(data-placeholder);
  color: #a9a1b8;
  pointer-events: none;
}

@media (min-width: 640px) {
  .rich-editor-select {
    width: auto;
  }
}

@media (max-width: 639px) {
  .rich-editor-toolbar {
    padding: 14px;
  }

  .rich-editor-group {
    width: 100%;
    justify-content: space-between;
  }
}
</style>
