/**
 * amis-ui v6.12.0-beta.0
 * Copyright 2018-2025 fex
 */

import { __extends, __awaiter, __generator, __spreadArray, __read, __rest, __decorate, __metadata } from 'tslib';
import React__default from 'react';
import { eachTree, parse, resolveVariableAndFilterForAsync, autobind, uncontrollable, themeable, localeable } from 'amis-core';
import { editorFactory } from './plugin.js';
import FuncList from './FuncList.js';
import VariableList from './VariableList.js';
import { toast } from '../Toast.js';
import Switch from '../Switch.js';
import CodeEditor from './CodeEditor.js';
import { getFunctionsDoc } from 'amis-formula';
import Transition, { EXITED, EXITING, ENTERING } from 'react-transition-group/Transition';
import MonacoEditor from '../Editor.js';
import debounce from 'lodash/debounce';

var _a;
var collapseStyles = (_a = {},
    _a[EXITED] = 'out',
    _a[EXITING] = 'out',
    _a[ENTERING] = 'in',
    _a);
var FormulaEditor = /** @class */ (function (_super) {
    __extends(FormulaEditor, _super);
    function FormulaEditor(props) {
        var _this = _super.call(this, props) || this;
        _this.state = {
            focused: false,
            isCodeMode: false,
            showRunPanel: false,
            expandTree: false,
            functions: _this.props.functions,
            runContext: '{\n}',
            runResult: '',
            runValid: false
        };
        _this.unmounted = false;
        _this.editor = React__default.createRef();
        _this.runCode = debounce(_this.runCode.bind(_this), 250, {
            leading: false,
            trailing: true
        });
        return _this;
    }
    FormulaEditor.buildFunctions = function (functions, functionsFilter) {
        return __awaiter(this, void 0, void 0, function () {
            var builtInFunctions, customFunctions, functionList;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, getFunctionsDoc()];
                    case 1:
                        builtInFunctions = _a.sent();
                        customFunctions = Array.isArray(functions) ? functions : [];
                        functionList = __spreadArray(__spreadArray([], __read(builtInFunctions), false), __read(customFunctions), false);
                        if (functionsFilter) {
                            return [2 /*return*/, functionsFilter(functionList)];
                        }
                        return [2 /*return*/, functionList];
                }
            });
        });
    };
    FormulaEditor.replaceStrByIndex = function (str, idx, key, replaceKey) {
        var from = str.slice(0, idx);
        var left = str.slice(idx);
        return from + left.replace(key, replaceKey);
    };
    FormulaEditor.getRegExpByMode = function (evalMode, key) {
        var reg = evalMode
            ? "\\b".concat(key, "\\b")
            : "\\$\\{[^\\{\\}]*\\b".concat(key, "\\b[^\\{\\}]*\\}");
        return new RegExp(reg);
    };
    /**
     * 干不掉，太多地方使用了，但是要废弃了。
     * 不要用了，输入框也换成 codemirror 了，本身就支持高亮
     * @deprecated
     * @param value
     * @param variables
     * @param evalMode
     * @returns
     */
    FormulaEditor.highlightValue = function (value, variables, evalMode, sourceCode) {
        if (evalMode === void 0) { evalMode = true; }
        if (sourceCode === void 0) { sourceCode = true; }
        if (!Array.isArray(variables) || !variables.length || !value) {
            return;
        }
        if (typeof value !== 'string') {
            try {
                value = JSON.stringify(value);
            }
            catch (error) {
                console.error('[amis][formula] given value is not a string');
                value = '';
            }
        }
        var varMap = {};
        eachTree(variables, function (item) {
            var _a;
            if (item.value) {
                var key = item.value;
                varMap[key] = (_a = item.path) !== null && _a !== void 0 ? _a : item.label;
            }
        });
        var vars = Object.keys(varMap)
            .filter(function (item) { return item; })
            .sort(function (a, b) { return b.length - a.length; });
        var content = value || '';
        var html = '';
        // 标记方法调用
        html = content.replace(/([A-Z]+)\s*\(/g, function (_, func, pos) {
            return _ === null || _ === void 0 ? void 0 : _.replace(func, "<span class=\"c-func\">".concat(func, "</span>"));
        });
        var REPLACE_KEY = 'AMIS_FORMULA_REPLACE_KEY';
        vars.forEach(function (v) {
            var from = 0;
            var idx = -1;
            while (~(idx = content.indexOf(v, from))) {
                var encodeHtml = FormulaEditor.replaceStrByIndex(html, idx, v, REPLACE_KEY);
                var reg = FormulaEditor.getRegExpByMode(evalMode, REPLACE_KEY);
                // 如果匹配到则高亮，没有匹配到替换成原值
                if (reg.test(encodeHtml)) {
                    html = encodeHtml.replace(REPLACE_KEY, "<span class=\"c-field\">".concat(sourceCode ? v : varMap[v], "</span>"));
                }
                else {
                    html = encodeHtml.replace(REPLACE_KEY, v);
                }
                from = idx + v.length;
            }
        });
        return { html: html };
    };
    FormulaEditor.prototype.componentDidMount = function () {
        return __awaiter(this, void 0, void 0, function () {
            var functionList;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!!this.state.functions) return [3 /*break*/, 2];
                        return [4 /*yield*/, FormulaEditor.buildFunctions()];
                    case 1:
                        functionList = _a.sent();
                        if (this.unmounted) {
                            return [2 /*return*/];
                        }
                        this.setState({
                            functions: functionList
                        });
                        _a.label = 2;
                    case 2: return [2 /*return*/];
                }
            });
        });
    };
    FormulaEditor.prototype.componentDidUpdate = function (prevProps) {
        if (prevProps.functions !== this.props.functions) {
            this.setState({
                functions: this.props.functions
            });
        }
    };
    FormulaEditor.prototype.componentWillUnmount = function () {
        this.unmounted = true;
        this.runCode.cancel();
    };
    FormulaEditor.prototype.handleFocus = function () {
        this.setState({
            focused: true
        });
    };
    FormulaEditor.prototype.handleBlur = function () {
        this.setState({
            focused: false
        });
    };
    FormulaEditor.prototype.getEditor = function () {
        var ref = this.editor.current;
        while (ref === null || ref === void 0 ? void 0 : ref.getWrappedInstance) {
            ref = ref.getWrappedInstance();
        }
        return ref;
    };
    FormulaEditor.prototype.insertValue = function (value, type) {
        var _a;
        (_a = this.getEditor()) === null || _a === void 0 ? void 0 : _a.insertContent(value, type);
    };
    FormulaEditor.prototype.validate = function () {
        var value = this.props.value;
        try {
            value
                ? parse(value, {
                    evalMode: this.props.evalMode
                })
                : null;
        }
        catch (e) {
            return e.message;
        }
        return;
    };
    FormulaEditor.prototype.handleFunctionSelect = function (item) {
        var _a;
        (_a = this.getEditor()) === null || _a === void 0 ? void 0 : _a.insertContent("".concat(item.name), 'func');
    };
    FormulaEditor.prototype.handleVariableSelect = function (item) {
        var _a;
        var selfVariableName = this.props.selfVariableName;
        if (item &&
            item.value &&
            selfVariableName &&
            selfVariableName === item.value) {
            toast.warning('不能使用当前变量[self]，避免循环引用。');
            return;
        }
        if (!item.value) {
            return;
        }
        (_a = this.getEditor()) === null || _a === void 0 ? void 0 : _a.insertContent(item.isMember
            ? item.value
            : {
                key: item.value,
                name: item.label,
                path: item.path
                // chunks: item.chunks
            }, item.isMember ? undefined : 'variable', 'cm-field', !this.state.isCodeMode);
    };
    FormulaEditor.prototype.handleOnChange = function (value) {
        var onChange = this.props.onChange;
        onChange === null || onChange === void 0 ? void 0 : onChange(value);
        this.runCode();
    };
    FormulaEditor.prototype.editorFactory = function (dom, cm) {
        var _a = this.props; _a.editorOptions; var rest = __rest(_a, ["editorOptions"]);
        return editorFactory(dom, cm, rest, {
            lineWrapping: true,
            autoFocus: true
        });
    };
    FormulaEditor.prototype.handleIsCodeModeChange = function (showCode) {
        var _this = this;
        // 重置一下value
        // this.getEditor()?.setValue(this.getEditor()?.getValue());
        // 非源码模式，则mark一下
        // !showCode && this.getEditor()?.autoMarkText();
        this.setState({ isCodeMode: showCode }, function () { var _a; return (_a = _this.getEditor()) === null || _a === void 0 ? void 0 : _a.setDisableAutoMark(showCode ? true : false); });
    };
    FormulaEditor.prototype.toggleRunPanel = function () {
        this.setState({
            showRunPanel: !this.state.showRunPanel
        }, this.runCode);
    };
    FormulaEditor.prototype.handleRunContextChange = function (value) {
        this.setState({ runContext: value }, this.runCode);
    };
    FormulaEditor.prototype.runCode = function () {
        return __awaiter(this, void 0, void 0, function () {
            var value, runContext, code, result, e_1;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        value = this.props.value || '';
                        if (!this.state.showRunPanel) {
                            return [2 /*return*/];
                        }
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        // 因为 resolveVariableAndFilterForAsync 不会报语法错误
                        parse(value, {
                            evalMode: this.props.evalMode
                        });
                        runContext = JSON.parse(this.state.runContext);
                        code = this.props.evalMode ? "${".concat(value, "}") : value;
                        return [4 /*yield*/, resolveVariableAndFilterForAsync(code, runContext)];
                    case 2:
                        result = _a.sent();
                        this.unmounted ||
                            this.setState({
                                runValid: true,
                                runResult: JSON.stringify(result)
                            });
                        return [3 /*break*/, 4];
                    case 3:
                        e_1 = _a.sent();
                        this.unmounted ||
                            this.setState({
                                runValid: false,
                                runResult: e_1.message
                            });
                        return [3 /*break*/, 4];
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    FormulaEditor.prototype.handleExpandTreeChange = function (expand) {
        this.setState({ expandTree: expand });
    };
    FormulaEditor.prototype.render = function () {
        var _this = this;
        var _a = this.props, header = _a.header, value = _a.value, variables = _a.variables, variableMode = _a.variableMode, __ = _a.translate, cx = _a.classnames, variableClassName = _a.variableClassName, functionClassName = _a.functionClassName, classPrefix = _a.classPrefix, selfVariableName = _a.selfVariableName, evalMode = _a.evalMode, simplifyMemberOprs = _a.simplifyMemberOprs, _b = _a.enableRunPanel, enableRunPanel = _b === void 0 ? true : _b;
        var _c = this.state, focused = _c.focused, isCodeMode = _c.isCodeMode, showRunPanel = _c.showRunPanel, expandTree = _c.expandTree, functions = _c.functions, runContext = _c.runContext, runResult = _c.runResult, runValid = _c.runValid;
        return (React__default.createElement("div", { className: cx("FormulaEditor", {
                'is-focused': focused
            }) },
            React__default.createElement("section", { className: cx('FormulaEditor-settings') },
                React__default.createElement(FuncList, { className: functionClassName, title: __('FormulaEditor.function'), data: functions || [], onSelect: this.handleFunctionSelect }),
                React__default.createElement("div", { className: cx("FormulaEditor-content") },
                    React__default.createElement("header", { className: cx("FormulaEditor-header") },
                        __(header || 'FormulaEditor.title'),
                        enableRunPanel ? (React__default.createElement("div", { className: cx("FormulaEditor-header-toolbar m-l") },
                            React__default.createElement("span", null, __('FormulaEditor.run')),
                            React__default.createElement(Switch, { value: showRunPanel, onChange: this.toggleRunPanel }))) : null,
                        React__default.createElement("div", { className: cx("FormulaEditor-header-toolbar") },
                            React__default.createElement("span", null, __('FormulaEditor.sourceMode')),
                            React__default.createElement(Switch, { value: isCodeMode, onChange: this.handleIsCodeModeChange }))),
                    React__default.createElement(CodeEditor, { evalMode: evalMode, functions: functions, variables: variables, className: cx('FormulaEditor-editor'), value: value, onChange: this.handleOnChange, ref: this.editor, onFocus: this.handleFocus, onBlur: this.handleBlur, autoFocus: true }),
                    React__default.createElement(Transition, { mountOnEnter: true, unmountOnExit: true, key: "run-panel", in: showRunPanel, timeout: 300 }, function (status) {
                        return (React__default.createElement("div", { className: cx("FormulaEditor-runPanel", collapseStyles[status]) },
                            React__default.createElement("div", { className: cx("FormulaEditor-runPanel-context") },
                                React__default.createElement("header", null, __('FormulaEditor.runContext')),
                                React__default.createElement("div", null,
                                    React__default.createElement(MonacoEditor, { value: runContext, onChange: _this.handleRunContextChange, language: "json", options: {
                                            tabSize: 2,
                                            lineNumbers: false
                                        } }))),
                            React__default.createElement("div", { className: cx("FormulaEditor-runPanel-result", runValid ? '' : 'is-error') },
                                React__default.createElement("header", null, __('FormulaEditor.runResult')),
                                React__default.createElement("div", null, runResult))));
                    })),
                React__default.createElement("div", { className: cx('FormulaEditor-panel', 'right') },
                    variableMode !== 'tabs' ? (React__default.createElement("div", { className: cx('FormulaEditor-panel-header') },
                        __('FormulaEditor.variable'),
                        variableMode === 'tree' ? (React__default.createElement("div", { className: cx("FormulaEditor-header-toolbar") },
                            React__default.createElement("span", null, __('FormulaEditor.toggleAll')),
                            React__default.createElement(Switch, { value: expandTree, onChange: this.handleExpandTreeChange }))) : null)) : null,
                    React__default.createElement("div", { className: cx('FormulaEditor-panel-body', variableMode && "FormulaEditor-panel-body--".concat(variableMode)) },
                        React__default.createElement(VariableList, { classPrefix: classPrefix, className: cx('FormulaEditor-VariableList', 'FormulaEditor-VariableList-root', variableClassName), expandTree: expandTree, selectMode: variableMode, data: variables, onSelect: this.handleVariableSelect, selfVariableName: selfVariableName, simplifyMemberOprs: simplifyMemberOprs }))))));
    };
    FormulaEditor.defaultProps = {
        variables: [],
        evalMode: true
    };
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", []),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "handleFocus", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", []),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "handleBlur", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object, String]),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "insertValue", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", []),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "validate", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object]),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "handleFunctionSelect", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object]),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "handleVariableSelect", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object]),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "handleOnChange", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [HTMLElement, Object]),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "editorFactory", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Boolean]),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "handleIsCodeModeChange", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", []),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "toggleRunPanel", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [String]),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "handleRunContextChange", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Boolean]),
        __metadata("design:returntype", void 0)
    ], FormulaEditor.prototype, "handleExpandTreeChange", null);
    return FormulaEditor;
}(React__default.Component));
var Editor = uncontrollable(themeable(localeable(FormulaEditor)), {
    value: 'onChange'
}, ['validate']);

export { FormulaEditor, Editor as default };
