<script setup lang="ts">
import type { IDomEditor } from '@wangeditor/editor';

import { nextTick, onBeforeUnmount, ref, shallowRef, watch } from 'vue';

import { EasyFlowFormModal } from '@easyflow/common-ui';
import { $t } from '@easyflow/locales';

import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import DOMPurify from 'dompurify';
import {
  ElForm,
  ElFormItem,
  ElInput,
  ElMessage,
  ElTreeSelect,
} from 'element-plus';

import { api } from '#/api/request';
import { buildKnowledgePath } from '#/views/ai/documentCollection/share-path';

import '@wangeditor/editor/dist/css/style.css';

const props = defineProps({
  modelValue: {
    type: Boolean,
    default: false,
  },
  data: {
    type: Object as any,
    default: () => ({}),
  },
  categoryOptions: {
    type: Array as any,
    default: () => [],
  },
  requestClient: {
    type: Object as any,
    default: () => api,
  },
  endpointPrefix: {
    type: String,
    default: '',
  },
});

const emit = defineEmits(['submit', 'update:modelValue']);
const MAX_IMAGE_SIZE = 5 * 1024 * 1024;
const ALLOWED_IMAGE_TYPES = new Set([
  'image/gif',
  'image/jpeg',
  'image/png',
  'image/webp',
]);

const editorRef = shallowRef<IDomEditor | null>(null);
const form = ref<any>({
  id: '',
  collectionId: '',
  categoryId: '',
  question: '',
  answerHtml: '',
  orderNo: 0,
});

watch(
  () => props.data,
  (newData: any) => {
    form.value = {
      id: newData?.id || '',
      collectionId: newData?.collectionId || '',
      categoryId:
        newData?.categoryId === undefined || newData?.categoryId === null
          ? ''
          : String(newData.categoryId),
      question: newData?.question || '',
      answerHtml: newData?.answerHtml || '',
      orderNo: newData?.orderNo ?? 0,
    };
  },
  { immediate: true, deep: true },
);

const toolbarConfig = {
  excludeKeys: ['insertVideo', 'group-video', 'uploadVideo', 'todo', 'emotion'],
};
const editorConfig: any = {
  placeholder: $t('documentCollection.faq.answerPlaceholder'),
  MENU_CONF: {
    uploadImage: {
      customUpload: async (
        file: File,
        insertFn: (url: string, alt?: string, href?: string) => void,
      ) => {
        if (!form.value.collectionId) {
          ElMessage.error($t('documentCollection.faq.collectionRequired'));
          return;
        }
        if (!ALLOWED_IMAGE_TYPES.has(file.type)) {
          ElMessage.error($t('documentCollection.faq.imageTypeInvalid'));
          return;
        }
        if (file.size > MAX_IMAGE_SIZE) {
          ElMessage.error($t('documentCollection.faq.imageSizeExceeded'));
          return;
        }

        try {
          const res = await props.requestClient.upload(
            buildKnowledgePath(
              props.endpointPrefix,
              '/api/v1/faqItem/uploadImage',
            ),
            { collectionId: form.value.collectionId, file },
            {},
          );
          const imageUrl = res?.data?.path;
          if (!imageUrl) {
            ElMessage.error($t('documentCollection.faq.imageUploadFailed'));
            return;
          }
          insertFn(imageUrl, file.name, imageUrl);
        } catch (error) {
          console.error('FAQ image upload failed:', error);
          ElMessage.error($t('documentCollection.faq.imageUploadFailed'));
        }
      },
    },
  },
};

const handleEditorCreated = (editor: IDomEditor) => {
  editorRef.value = editor;
};

const focusAnswerEditor = () => {
  const editor = editorRef.value as any;
  if (editor && typeof editor.focus === 'function') {
    try {
      editor.focus(true);
    } catch {
      editor.focus();
    }
  }
  nextTick(() => {
    const editableEl = document.querySelector(
      '.faq-edit-dialog .w-e-text-container [contenteditable="true"]',
    ) as HTMLElement | null;
    editableEl?.focus();
  });
};

const handleQuestionKeydown = (event: Event | KeyboardEvent) => {
  if (
    event instanceof KeyboardEvent &&
    event.key === 'Tab' &&
    !event.shiftKey
  ) {
    event.preventDefault();
    focusAnswerEditor();
  }
};

const closeDialog = () => {
  emit('update:modelValue', false);
};

const handleSubmit = () => {
  if (!form.value.question?.trim()) {
    ElMessage.error($t('documentCollection.faq.questionRequired'));
    return;
  }
  const sanitizedHtml = DOMPurify.sanitize(form.value.answerHtml || '', {
    ADD_TAGS: ['img'],
    ADD_ATTR: ['src', 'alt', 'title', 'width', 'height'],
    ALLOWED_URI_REGEXP: /^https?:\/\//i,
  });
  const doc = new DOMParser().parseFromString(sanitizedHtml, 'text/html');
  const pureText = (doc.body?.textContent || '').trim();
  const hasImage = doc.querySelector('img[src]') !== null;
  if (!pureText && !hasImage) {
    ElMessage.error($t('documentCollection.faq.answerRequired'));
    return;
  }
  emit('submit', {
    ...form.value,
    question: form.value.question.trim(),
    answerHtml: sanitizedHtml,
    orderNo: Number(form.value.orderNo) || 0,
    categoryId: form.value.categoryId || null,
  });
};

onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor) {
    editor.destroy();
  }
});
</script>

<template>
  <EasyFlowFormModal
    class="faq-edit-dialog"
    :open="modelValue"
    :title="form.id ? $t('button.edit') : $t('button.add')"
    width="min(920px, 92vw)"
    :confirm-text="$t('button.save')"
    @update:open="emit('update:modelValue', $event)"
    @cancel="closeDialog"
    @confirm="handleSubmit"
  >
    <ElForm
      class="faq-form easyflow-modal-form easyflow-modal-form--compact"
      label-position="top"
    >
      <ElFormItem :label="$t('documentCollection.faq.category')">
        <ElTreeSelect
          v-model="form.categoryId"
          check-strictly
          clearable
          :data="categoryOptions"
          node-key="id"
          :props="{ label: 'categoryName', children: 'children' }"
          :placeholder="$t('documentCollection.faq.categoryPlaceholder')"
        />
      </ElFormItem>
      <ElFormItem :label="$t('documentCollection.faq.question')">
        <ElInput
          v-model="form.question"
          :placeholder="$t('documentCollection.faq.questionPlaceholder')"
          @keydown="handleQuestionKeydown"
        />
        <div class="field-tip">Tab 可快速跳转到答案编辑区域</div>
      </ElFormItem>
      <ElFormItem :label="$t('documentCollection.faq.answer')">
        <div class="editor-wrapper">
          <Toolbar
            :editor="editorRef"
            :default-config="toolbarConfig"
            mode="default"
          />
          <Editor
            v-model="form.answerHtml"
            :default-config="editorConfig"
            mode="default"
            @on-created="handleEditorCreated"
          />
        </div>
      </ElFormItem>
    </ElForm>
  </EasyFlowFormModal>
</template>

<style scoped>
.faq-form :deep(.el-form-item__label) {
  padding-bottom: 8px;
  font-weight: 600;
}

.faq-form :deep(.el-form-item) {
  margin-bottom: 18px;
}

.faq-form :deep(.el-input__wrapper),
.faq-form :deep(.el-select__wrapper) {
  min-height: 42px;
  border-radius: 10px;
  transition: box-shadow 0.2s ease;
}

.faq-form :deep(.el-input__wrapper.is-focus),
.faq-form :deep(.el-select__wrapper.is-focused) {
  box-shadow: 0 0 0 1px var(--el-color-primary) inset;
}

.field-tip {
  margin-top: 6px;
  font-size: 12px;
  line-height: 18px;
  color: var(--el-text-color-secondary);
}

.editor-wrapper {
  width: 100%;
  overflow: hidden;
  background: var(--el-fill-color-blank);
  border: 1px solid var(--el-border-color-lighter);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgb(15 23 42 / 4%);
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

.editor-wrapper:focus-within {
  border-color: var(--el-color-primary);
  box-shadow: 0 0 0 3px rgb(64 158 255 / 12%);
}

:deep(.w-e-toolbar) {
  padding: 8px 10px;
  background: var(--el-fill-color-blank);
  border-bottom: 1px solid var(--el-border-color-light);
}

:deep(.w-e-text-container) {
  height: 340px;
  min-height: 340px;
  cursor: text;
  background: var(--el-fill-color-blank);
}

:deep(.w-e-text-container .w-e-scroll) {
  cursor: text;
}

:deep(.w-e-text-container [data-slate-editor]) {
  min-height: 100%;
  padding: 12px;
  cursor: text;
}

:deep(.w-e-text-container [data-slate-editor] p) {
  cursor: text;
}

.dialog-footer {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
}

.footer-btn {
  min-width: 88px;
}

:deep(.faq-edit-dialog .el-dialog) {
  overflow: hidden;
  border-radius: 14px;
}

:deep(.faq-edit-dialog .el-dialog__header) {
  padding: 18px 22px;
  margin-right: 0;
  border-bottom: 1px solid var(--el-border-color-lighter);
}

:deep(.faq-edit-dialog .el-dialog__body) {
  padding: 18px 22px 16px;
}

:deep(.faq-edit-dialog .el-dialog__footer) {
  padding: 12px 22px 18px;
  border-top: 1px solid var(--el-border-color-lighter);
}
</style>
