"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PromptEditor = void 0;
const i18n_1 = __importDefault(require("../../../../../../../locales/i18n.js"));
const react_1 = __importStar(require("react"));
const cn_ui_1 = require("@cainiaofe/cn-ui");
const cn_domain_popup_1 = require("@cainiaofe/cn-domain-popup");
const floating_layer_1 = require("../../../../../../../utils/floating-layer.js");
const constants_1 = require("../constants");
require("./index.scss");
/** 变量标记的属性名 */
const VARIABLE_ATTR = 'data-variable';
const FieldSelectorPopup = ({ visible, onVisibleChange, fields, insertedFields, onSelect, trigger, placement = 'bottom-start', }) => {
    const [searchValue, setSearchValue] = (0, react_1.useState)('');
    // 过滤字段
    const filteredFields = fields.filter((field) => {
        var _a, _b;
        return ((_a = field.title) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(searchValue === null || searchValue === void 0 ? void 0 : searchValue.toLowerCase())) ||
            ((_b = field.dataIndex) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes(searchValue === null || searchValue === void 0 ? void 0 : searchValue.toLowerCase()));
    });
    // 按分组组织字段
    const groupedFields = (() => {
        const groups = {};
        filteredFields.forEach((field) => {
            const group = field.group || i18n_1.default.get({ id: 'Field', dm: '字段' });
            if (!groups[group]) {
                groups[group] = [];
            }
            groups[group].push(field);
        });
        return groups;
    })();
    const handleSelect = (field) => {
        onSelect(field);
        onVisibleChange(false);
        setSearchValue('');
    };
    return (react_1.default.createElement(cn_domain_popup_1.Popup, { visible: visible, onVisibleChange: (v) => {
            onVisibleChange(v);
            if (!v)
                setSearchValue('');
        }, trigger: trigger, placement: placement, offset: 4, container: floating_layer_1.getPopupContainer },
        react_1.default.createElement("div", { className: "prompt-editor-field-selector" },
            react_1.default.createElement("div", { className: "prompt-editor-field-selector-search" },
                react_1.default.createElement(cn_ui_1.CnInput, { placeholder: i18n_1.default.get({ id: 'EnterSearchContent', dm: '输入搜索内容' }), value: searchValue, onChange: setSearchValue, style: { width: '100%' } })),
            react_1.default.createElement("div", { className: "prompt-editor-field-selector-list" },
                Object.entries(groupedFields).map(([groupName, groupFields]) => (react_1.default.createElement("div", { key: groupName, className: "prompt-editor-field-group" },
                    react_1.default.createElement("div", { className: "prompt-editor-field-group-items" }, groupFields.map((field) => (react_1.default.createElement("div", { key: field.dataIndex, className: `prompt-editor-field-item ${insertedFields.includes(field.dataIndex) ? 'selected' : ''}`, onClick: () => handleSelect(field) },
                        react_1.default.createElement(cn_ui_1.CnIcon, { type: field.icon || 'edit', size: "small", style: { color: '#666' } }),
                        react_1.default.createElement("span", null, field.title)))))))),
                Object.keys(groupedFields).length === 0 && (react_1.default.createElement("div", { className: "prompt-editor-field-empty" }, i18n_1.default.get({ id: 'NoFieldsAvailable', dm: '暂无可用字段' })))))));
};
/**
 * Prompt 编辑器组件
 * 支持在文本中插入变量标签，变量以 ${variableName} 格式存储
 */
exports.PromptEditor = (0, react_1.forwardRef)(({ value = '', onChange, fields = [], placeholder = i18n_1.default.get({ id: 'PleaseEnterContent', dm: '请输入内容...' }), hasError = false, disabled = false, minHeight = 120, model: _modelProp, onModelChange: _onModelChange, }, ref) => {
    const editorRef = (0, react_1.useRef)(null);
    const [fieldSelectorVisible, setFieldSelectorVisible] = (0, react_1.useState)(false);
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const [_modelSelectorVisible, _setModelSelectorVisible] = (0, react_1.useState)(false);
    const [cursorPosition, setCursorPosition] = (0, react_1.useState)(null);
    // 用于跟踪当前正在编辑的变量
    const [editingVariable, setEditingVariable] = (0, react_1.useState)(null);
    const [editingVariableVisible, setEditingVariableVisible] = (0, react_1.useState)(false);
    const [editingPosition, setEditingPosition] = (0, react_1.useState)(null);
    const editingVirtualReference = (0, react_1.useMemo)(() => {
        if (!editingPosition) {
            return undefined;
        }
        return {
            getBoundingClientRect: () => ({
                x: editingPosition.x,
                y: editingPosition.y,
                top: editingPosition.y,
                left: editingPosition.x,
                right: editingPosition.x,
                bottom: editingPosition.y,
                width: 0,
                height: 0,
            }),
        };
    }, [editingPosition]);
    // 模型选择器暂未接入，先保留默认模型常量避免未来切回时改动接口。
    const [_internalModel] = (0, react_1.useState)(constants_1.DEFAULT_MODEL);
    // 解析值中的变量
    const parseVariables = (text) => {
        const regex = /\$\{(\w+)\}/g;
        const variables = [];
        let match = regex.exec(text);
        while (match !== null) {
            if (!variables.includes(match[1])) {
                variables.push(match[1]);
            }
            match = regex.exec(text);
        }
        return variables;
    };
    // 获取字段显示名称
    const getFieldTitle = (0, react_1.useCallback)((dataIndex) => {
        const field = fields.find((f) => f.dataIndex === dataIndex);
        return (field === null || field === void 0 ? void 0 : field.title) || dataIndex;
    }, [fields]);
    // 获取当前已插入的字段
    const insertedFields = value ? parseVariables(value) : [];
    // 更换变量字段
    const handleChangeVariable = (0, react_1.useCallback)((oldDataIndex, newField) => {
        if (!value)
            return;
        // 替换 ${oldDataIndex} 为 ${newField.dataIndex}
        const newValue = value.replace(new RegExp(`\\$\\{${oldDataIndex}\\}`, 'g'), `\${${newField.dataIndex}}`);
        onChange === null || onChange === void 0 ? void 0 : onChange(newValue);
        setEditingVariable(null);
        setEditingVariableVisible(false);
        setEditingPosition(null);
    }, [value, onChange]);
    // 将值转换为 HTML（变量转为标签）
    const valueToHtml = (0, react_1.useCallback)((text) => {
        if (!text)
            return '';
        const escapeHtml = (str) => {
            return str
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#039;');
        };
        return text.replace(/\$\{(\w+)\}/g, (match, varName) => {
            const title = getFieldTitle(varName);
            return `<span class="prompt-editor-variable prompt-editor-variable--editable" ${VARIABLE_ATTR}="${varName}" contenteditable="false">${escapeHtml(title)}<i class="prompt-editor-variable-dropdown"></i></span>`;
        });
    }, [getFieldTitle]);
    // 将 HTML 转换为值（标签转为变量）
    const htmlToValue = (0, react_1.useCallback)((html) => {
        if (!html)
            return '';
        const temp = document.createElement('div');
        temp.innerHTML = html;
        const processNode = (node) => {
            if (node.nodeType === Node.TEXT_NODE) {
                return node.textContent || '';
            }
            if (node.nodeType === Node.ELEMENT_NODE) {
                const element = node;
                if (element.hasAttribute(VARIABLE_ATTR)) {
                    const varName = element.getAttribute(VARIABLE_ATTR);
                    return `\${${varName}}`;
                }
                if (element.tagName === 'BR') {
                    return '\n';
                }
                if (element.tagName === 'DIV' || element.tagName === 'P') {
                    const childContent = Array.from(element.childNodes).map(processNode).join('');
                    return element.previousSibling ? `\n${childContent}` : childContent;
                }
                return Array.from(element.childNodes).map(processNode).join('');
            }
            return '';
        };
        return Array.from(temp.childNodes).map(processNode).join('');
    }, []);
    // 初始化编辑器内容
    (0, react_1.useEffect)(() => {
        if (editorRef.current) {
            const currentHtml = editorRef.current.innerHTML;
            const newHtml = valueToHtml(value);
            if (htmlToValue(currentHtml) !== value) {
                editorRef.current.innerHTML = newHtml;
            }
        }
    }, [value, valueToHtml, htmlToValue]);
    // 保存光标位置
    const saveCursorPosition = (0, react_1.useCallback)(() => {
        const selection = window.getSelection();
        if (selection && selection.rangeCount > 0) {
            setCursorPosition(selection.getRangeAt(0).cloneRange());
        }
    }, []);
    // 恢复光标位置
    const restoreCursorPosition = (0, react_1.useCallback)(() => {
        if (cursorPosition && editorRef.current) {
            const selection = window.getSelection();
            if (selection) {
                selection.removeAllRanges();
                selection.addRange(cursorPosition);
            }
        }
    }, [cursorPosition]);
    // 处理输入变化
    const handleInput = (0, react_1.useCallback)(() => {
        if (editorRef.current && onChange) {
            const newValue = htmlToValue(editorRef.current.innerHTML);
            onChange(newValue);
        }
    }, [onChange, htmlToValue]);
    // 处理粘贴（只粘贴纯文本）
    const handlePaste = (0, react_1.useCallback)((e) => {
        e.preventDefault();
        const text = e.clipboardData.getData('text/plain');
        document.execCommand('insertText', false, text);
    }, []);
    // 处理点击事件（检测是否点击了变量标签）
    const handleClick = (0, react_1.useCallback)((e) => {
        if (disabled)
            return;
        const target = e.target;
        const variableElement = target.closest(`[${VARIABLE_ATTR}]`);
        if (variableElement) {
            e.preventDefault();
            e.stopPropagation();
            const varName = variableElement.getAttribute(VARIABLE_ATTR);
            if (varName) {
                // 获取被点击变量的位置
                const rect = variableElement.getBoundingClientRect();
                setEditingPosition({
                    x: rect.left,
                    y: rect.bottom,
                });
                setEditingVariable(varName);
                setEditingVariableVisible(true);
            }
        }
    }, [disabled]);
    // 处理按键（防止在变量标签内编辑）
    const handleKeyDown = (0, react_1.useCallback)((e) => {
        var _a;
        const selection = window.getSelection();
        if (!selection || selection.rangeCount === 0)
            return;
        const range = selection.getRangeAt(0);
        const container = range.startContainer;
        const variableElement = container.nodeType === Node.TEXT_NODE
            ? (_a = container.parentElement) === null || _a === void 0 ? void 0 : _a.closest(`[${VARIABLE_ATTR}]`)
            : container.closest(`[${VARIABLE_ATTR}]`);
        if (variableElement) {
            if (e.key === 'Backspace' || e.key === 'Delete') {
                e.preventDefault();
                variableElement.remove();
                handleInput();
            }
            else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
                e.preventDefault();
            }
        }
    }, [handleInput]);
    // 在光标位置插入字段
    const insertField = (0, react_1.useCallback)((field) => {
        if (!editorRef.current || disabled)
            return;
        editorRef.current.focus();
        const selection = window.getSelection();
        if (!selection)
            return;
        let range;
        if (selection.rangeCount > 0) {
            range = selection.getRangeAt(0);
        }
        else {
            range = document.createRange();
            range.selectNodeContents(editorRef.current);
            range.collapse(false);
        }
        const variableSpan = document.createElement('span');
        variableSpan.className = 'prompt-editor-variable prompt-editor-variable--editable';
        variableSpan.setAttribute(VARIABLE_ATTR, field.dataIndex);
        variableSpan.contentEditable = 'false';
        variableSpan.innerHTML = `${field.title}<i class="prompt-editor-variable-dropdown"></i>`;
        const spaceNode = document.createTextNode('\u00A0');
        range.deleteContents();
        range.insertNode(spaceNode);
        range.insertNode(variableSpan);
        range.setStartAfter(spaceNode);
        range.setEndAfter(spaceNode);
        selection.removeAllRanges();
        selection.addRange(range);
        handleInput();
    }, [disabled, handleInput]);
    // 获取已插入的字段
    const getInsertedFields = (0, react_1.useCallback)(() => {
        if (!editorRef.current)
            return [];
        const html = editorRef.current.innerHTML;
        const currentValue = htmlToValue(html);
        return parseVariables(currentValue);
    }, [htmlToValue]);
    // 聚焦
    const focus = (0, react_1.useCallback)(() => {
        var _a;
        (_a = editorRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }, []);
    // 暴露方法给父组件
    (0, react_1.useImperativeHandle)(ref, () => ({
        focus,
        insertField,
        getInsertedFields,
    }), [focus, insertField, getInsertedFields]);
    // 处理字段选择（底部工具栏）
    const handleFieldSelect = (field) => {
        insertField(field);
        setFieldSelectorVisible(false);
    };
    // 关闭变量编辑弹层
    const handleCloseEditingPopup = () => {
        setEditingVariableVisible(false);
        setEditingVariable(null);
        setEditingPosition(null);
    };
    const renderEditingVariablePopup = () => {
        if (!editingVariable || !editingVirtualReference)
            return null;
        return (react_1.default.createElement(cn_domain_popup_1.Popup, { visible: editingVariableVisible, onVisibleChange: (v) => {
                if (!v)
                    handleCloseEditingPopup();
            }, virtualReference: editingVirtualReference, align: "bl", offset: 4, container: floating_layer_1.getPopupContainer },
            react_1.default.createElement("div", { className: "prompt-editor-field-selector" },
                react_1.default.createElement("div", { className: "prompt-editor-field-selector-search" },
                    react_1.default.createElement(cn_ui_1.CnInput, { placeholder: i18n_1.default.get({ id: 'EnterSearchContent', dm: '输入搜索内容' }), style: { width: '100%' } })),
                react_1.default.createElement("div", { className: "prompt-editor-field-selector-list" },
                    fields.map((field) => (react_1.default.createElement("div", { key: field.dataIndex, className: `prompt-editor-field-item ${insertedFields.includes(field.dataIndex) ? 'selected' : ''}`, onClick: () => handleChangeVariable(editingVariable, field) },
                        react_1.default.createElement(cn_ui_1.CnIcon, { type: field.icon || 'edit', size: "small", style: { color: '#666' } }),
                        react_1.default.createElement("span", null, field.title)))),
                    fields.length === 0 && (react_1.default.createElement("div", { className: "prompt-editor-field-empty" }, i18n_1.default.get({ id: 'NoFieldsAvailable', dm: '暂无可用字段' })))))));
    };
    return (react_1.default.createElement("div", { className: `prompt-editor ${hasError ? 'has-error' : ''} ${disabled ? 'disabled' : ''}` },
        react_1.default.createElement("div", { className: "prompt-editor-content-wrapper", style: { minHeight } },
            react_1.default.createElement("div", { ref: editorRef, className: "prompt-editor-content", contentEditable: !disabled, onInput: handleInput, onPaste: handlePaste, onKeyDown: handleKeyDown, onClick: handleClick, onBlur: saveCursorPosition, onFocus: restoreCursorPosition, "data-placeholder": placeholder, suppressContentEditableWarning: true })),
        renderEditingVariablePopup(),
        react_1.default.createElement("div", { className: "prompt-editor-toolbar" },
            react_1.default.createElement(FieldSelectorPopup, { visible: fieldSelectorVisible, onVisibleChange: setFieldSelectorVisible, fields: fields, insertedFields: insertedFields, onSelect: handleFieldSelect, placement: "top-start", trigger: react_1.default.createElement("div", { className: "prompt-editor-insert-btn", onClick: () => !disabled && setFieldSelectorVisible(true) },
                    react_1.default.createElement(cn_ui_1.CnIcon, { type: "add", size: "small" }),
                    react_1.default.createElement("span", null, i18n_1.default.get({ id: 'InsertField', dm: '插入字段' }))) }))));
});
exports.PromptEditor.displayName = 'PromptEditor';
exports.default = exports.PromptEditor;
