<script setup lang="ts">
import { computed, h, ref } from "vue";
import { useI18n } from "vue-i18n";
import { ExperimentOutlined, ThunderboltOutlined, LoadingOutlined } from "@ant-design/icons-vue";
import type { KolVariableDefinition, KolVariableType } from "@geo/shared-types";
import { Modal } from "ant-design-vue";

import {
  buildKolPlaceholderToken,
  createKolVariableDefinition,
  findKolPlaceholderKeyAtPosition,
} from "@/lib/kol-placeholders";

const props = defineProps<{
  content: string;
  variables: KolVariableDefinition[];
  aiTaskId: string | null;
}>();

const emit = defineEmits<{
  (e: "update:content", value: string): void;
  (e: "update:variables", value: KolVariableDefinition[]): void;
  (e: "ai-generate", description: string): void;
  (e: "ai-optimize"): void;
  (e: "focus-variable", key: string): void;
}>();

const { t } = useI18n();
const aiDescription = ref("");
const textareaRef = ref<HTMLTextAreaElement | null>(null);
const highlightRef = ref<HTMLDivElement | null>(null);

const editorPlaceholder = "在这里输入提示词内容，可以使用 {{变量名}} 引用左侧定义的变量";
const highlightTokenRE = /\{\{\s*([^{}]+?)\s*\}\}/g;

const highlightedContent = computed(() => {
  const text = props.content ?? "";
  if (!text) {
    return `<span class="editor-placeholder">${escapeHtml(editorPlaceholder)}</span>`;
  }

  let html = "";
  let lastIndex = 0;

  for (const match of text.matchAll(highlightTokenRE)) {
    const matchIndex = match.index ?? 0;
    const token = match[0] ?? "";

    html += escapeHtml(text.slice(lastIndex, matchIndex));
    html += `<span class="token-highlight">${escapeHtml(token)}</span>`;
    lastIndex = matchIndex + token.length;
  }

  html += escapeHtml(text.slice(lastIndex));
  return html;
});

function onDrop(event: DragEvent) {
  event.preventDefault();
  const type = event.dataTransfer?.getData("application/kol-variable-type") as KolVariableType;
  if (!type) return;

  const labelValue = ref("");

  Modal.confirm({
    title: t("kol.manage.variable.label"),
    content: () => {
      return h("div", { style: { marginTop: "16px" } }, [
        h("input", {
          class: "ant-input",
          placeholder: t("common.inputPlease"),
          value: labelValue.value,
          onInput: (e: Event) => {
            labelValue.value = (e.target as HTMLInputElement).value;
          },
        }),
      ]);
    },
    onOk: () => {
      const key = labelValue.value.trim() || t(`kol.manage.variable.${type}`);
      const existingVariable = props.variables.find((variable) => variable.key === key);

      if (!existingVariable) {
        const newVar: KolVariableDefinition = createKolVariableDefinition(key, {
          type,
        });
        emit("update:variables", [...props.variables, newVar]);
      }

      insertToken(buildKolPlaceholderToken(key));
    },
  });
}

function insertToken(token: string) {
  if (!textareaRef.value) return;
  
  const el = textareaRef.value;
  const start = el.selectionStart;
  const end = el.selectionEnd;
  const text = props.content;
  
  const newContent = text.substring(0, start) + token + text.substring(end);
  emit("update:content", newContent);
  
  // Set cursor position after update
  setTimeout(() => {
    el.focus();
    el.setSelectionRange(start + token.length, start + token.length);
    syncScroll();
  }, 0);
}

function handleAiGenerate() {
  if (!aiDescription.value.trim()) return;
  emit("ai-generate", aiDescription.value);
}

function handleContentInput(event: Event) {
  emit("update:content", (event.target as HTMLTextAreaElement).value);
  syncScroll();
}

function handleCaretInteraction() {
  if (!textareaRef.value) {
    return;
  }

  requestAnimationFrame(() => {
    const textarea = textareaRef.value;
    if (!textarea) {
      return;
    }

    const key = findKolPlaceholderKeyAtPosition(props.content, textarea.selectionStart ?? -1);
    if (key) {
      emit("focus-variable", key);
    }
  });
}

function syncScroll() {
  if (!textareaRef.value || !highlightRef.value) {
    return;
  }

  highlightRef.value.scrollTop = textareaRef.value.scrollTop;
  highlightRef.value.scrollLeft = textareaRef.value.scrollLeft;
}

function escapeHtml(value: string): string {
  return value
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;");
}
</script>

<template>
  <div class="kol-prompt-edit-area" @dragover.prevent @drop="onDrop">
    <div class="ai-assist-bar">
      <a-input
        v-model:value="aiDescription"
        class="ai-input"
        :placeholder="t('kol.manage.editor.aiPlaceholder')"
        :disabled="!!aiTaskId"
        @press-enter="handleAiGenerate"
      >
        <template #prefix>
          <ExperimentOutlined style="color: #722ed1" />
        </template>
      </a-input>
      <a-button
        type="primary"
        class="ai-btn"
        :loading="!!aiTaskId"
        @click="handleAiGenerate"
      >
        <template #icon><ThunderboltOutlined /></template>
        {{ t('kol.manage.editor.aiGenerate') }}
      </a-button>
      <a-button
        class="ai-btn"
        :disabled="!content || !!aiTaskId"
        @click="emit('ai-optimize')"
      >
        {{ t('kol.manage.editor.aiOptimize') }}
      </a-button>
    </div>

    <div class="editor-container">
      <div v-if="aiTaskId" class="ai-loading-overlay">
        <div class="loading-content">
          <LoadingOutlined class="loading-icon" />
          <span>AI 正在思考中...</span>
        </div>
      </div>
      <div
        ref="highlightRef"
        class="prompt-highlight"
        aria-hidden="true"
        v-html="highlightedContent"
      ></div>
      <textarea
        ref="textareaRef"
        class="prompt-textarea"
        :value="content"
        :placeholder="editorPlaceholder"
        @input="handleContentInput"
        @mouseup="handleCaretInteraction"
        @keyup="handleCaretInteraction"
        @scroll="syncScroll"
      ></textarea>
    </div>
  </div>
</template>

<style scoped>
.kol-prompt-edit-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #fff;
  min-width: 0;
}

.ai-assist-bar {
  padding: 12px 16px;
  border-bottom: 1px solid #f0f0f0;
  display: flex;
  gap: 8px;
  background: #f9f0ff;
}

.ai-input {
  flex: 1;
}

.ai-btn {
  flex-shrink: 0;
}

.editor-container {
  flex: 1;
  position: relative;
  display: flex;
  overflow: hidden;
}

.prompt-highlight {
  position: absolute;
  inset: 0;
  overflow: auto;
  padding: 24px;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: inherit;
  font-size: 16px;
  line-height: 1.6;
  color: #262626;
  pointer-events: none;
  user-select: none;
}

.prompt-textarea {
  position: relative;
  z-index: 1;
  flex: 1;
  border: none;
  resize: none;
  padding: 24px;
  background: transparent;
  font-family: inherit;
  font-size: 16px;
  line-height: 1.6;
  outline: none;
  color: transparent;
  caret-color: #262626;
}

.prompt-textarea::placeholder {
  color: transparent;
}

.prompt-highlight :deep(.token-highlight) {
  color: #eb2f96;
  font-weight: 600;
}

.prompt-highlight :deep(.editor-placeholder) {
  color: #bfbfbf;
}

.ai-loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.7);
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: #722ed1;
}

.loading-icon {
  font-size: 32px;
}
</style>
