import { ContentState, convertFromRaw, EditorState, convertToRaw } from "draft-js";
import htmlToDraft from "html-to-draftjs";
import { StringDataDefinition } from "../../Common/Data/Definitions/StringDataDefinition";
import { DataUtilities } from "../../Common/DataUtilities";
import { EventLog } from "../../Common/Event/EventLog";
import { RuleExecutable } from "../../Common/Execution/RuleExecutable";
import { TextMergeTestResult, TextMergeValueTestResult } from "./TextMergeTestResult";
import { TextMergeUtility } from "./XTextMergeUtilities";
import { UndefinedDataDefinition } from "../../Common/Data/Definitions/UndefinedDataDefinition";
import { ValidationIssue } from "../../Common/IDesignValidationProvider";
import { TextMergeConstants } from "./TextMergeConstants";
import { XTextMergeExportType } from "./TextMergeExportType";
import { ObjectDataDefinition } from "../../Common/Data/Definitions/ObjectDataDefinition";
import TurndownService from "turndown";
export class XTextMergeDefinition extends RuleExecutable {
    constructor() {
        super();
        this._id = DataUtilities.generateUniqueId();
        this._outputType = XTextMergeExportType.HTML;
        this.isValidField = (field) => {
            try {
                return !!DataUtilities.getFieldFromDataDefinitionByProperty(this.getInputDefinition().fields, field, "name");
            }
            catch (e) {
                return false;
            }
        };
        const styleMap = {
            CODE: {
                backgroundColor: "rgba(0, 0, 0, 0.05)",
                fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
                fontSize: 16,
                padding: 2,
            },
            STRIKETHROUGH: {
                textDecoration: "line-through",
            },
            UNDERLINE: {
                textDecoration: "underline",
            },
            "fontfamily-inter": {
                fontFamily: "Inter",
            },
            "fontfamily-mulish": {
                fontFamily: "Mulish",
            },
        };
        for (let i = 0; i < 16; i++) {
            styleMap[`fontsize-${8 + i}`] = {
                fontSize: `${8 + i}px`,
            };
        }
        for (let i = 0; i < 8; i++) {
            styleMap[`fontweight-${(i + 1) * 100}`] = {
                fontWeight: (i + 1) * 100,
            };
        }
        let editorState = EditorState.createEmpty();
        this._value = convertToRaw(editorState.getCurrentContent());
        this._styleMap = styleMap;
    }
    get styleMap() {
        return this._styleMap;
    }
    setValue(value) {
        const styleMap = {
            CODE: {
                backgroundColor: "rgba(0, 0, 0, 0.05)",
                fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
                fontSize: 16,
                padding: 2,
            },
            STRIKETHROUGH: {
                textDecoration: "line-through",
            },
            UNDERLINE: {
                textDecoration: "underline",
            },
            "fontfamily-inter": {
                fontFamily: "Inter",
            },
            "fontfamily-mulish": {
                fontFamily: "Mulish",
            },
        };
        for (let i = 0; i < 16; i++) {
            styleMap[`fontsize-${8 + i}`] = {
                fontSize: `${8 + i}px`,
            };
        }
        for (let i = 0; i < 8; i++) {
            styleMap[`fontweight-${(i + 1) * 100}`] = {
                fontWeight: (i + 1) * 100,
            };
        }
        if (value !== undefined && typeof value !== 'string') {
            console.log('value:', value, typeof value);
            this._value = value;
            for (let block of value.blocks) {
                for (let style of block.inlineStyleRanges) {
                    if (style.style.startsWith("color-")) {
                        styleMap[style.style] = {
                            color: `${style.style.replace("color-", "")}`,
                        };
                    }
                }
            }
        }
        else {
            const blocksFromHtml = htmlToDraft(value || "", (nodeName, element) => {
                var _a;
                let color = (_a = element.style) === null || _a === void 0 ? void 0 : _a.color;
                if (color && color !== "") {
                    color = color.replaceAll(", ", ",");
                    styleMap[`color-${color}`] = {
                        color: `${color}`,
                    };
                }
                return this.getEntityType(nodeName, element);
            });
            const { contentBlocks, entityMap } = blocksFromHtml;
            const contentState = ContentState.createFromBlockArray(contentBlocks, entityMap);
            let editorState = value ? EditorState.createWithContent(contentState) : EditorState.createEmpty();
            this._value = convertToRaw(editorState.getCurrentContent());
        }
        this._styleMap = styleMap;
    }
    set value(value) {
        const styleMap = {
            CODE: {
                backgroundColor: "rgba(0, 0, 0, 0.05)",
                fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
                fontSize: 16,
                padding: 2,
            },
            STRIKETHROUGH: {
                textDecoration: "line-through",
            },
            UNDERLINE: {
                textDecoration: "underline",
            },
            "fontfamily-inter": {
                fontFamily: "Inter",
            },
            "fontfamily-mulish": {
                fontFamily: "Mulish",
            },
        };
        for (let i = 0; i < 16; i++) {
            styleMap[`fontsize-${8 + i}`] = {
                fontSize: `${8 + i}px`,
            };
        }
        for (let i = 0; i < 8; i++) {
            styleMap[`fontweight-${(i + 1) * 100}`] = {
                fontWeight: (i + 1) * 100,
            };
        }
        this._value = value;
        for (let block of value.blocks) {
            for (let style of block.inlineStyleRanges) {
                if (style.style.startsWith("color-")) {
                    styleMap[style.style] = {
                        color: `${style.style.replace("color-", "")}`,
                    };
                }
            }
        }
        this._styleMap = styleMap;
    }
    get value() {
        return this._value;
    }
    get executionResult() {
        return this._executionResult;
    }
    set executionResult(value) {
        let val = typeof value === 'function' ? value() : value;
        if (!(val instanceof StringDataDefinition)) {
            throw new Error('can not set the executionResult with ' + val.type);
        }
        this._executionResult = value;
    }
    set outputType(type) {
        this._outputType = type;
        this.executionResult = () => {
            return new StringDataDefinition();
        };
    }
    get outputType() {
        return this._outputType;
    }
    run(data, testContext) {
        let result = '';
        let subContext;
        if (testContext) {
            subContext = new TextMergeTestResult(this._id);
            subContext.definition = this;
            testContext.addTestResultItem(subContext);
            subContext.addLogItem(new EventLog('XTextMerge: start evaluating Text Merge'));
        }
        if (this.value) {
            let rawState = this.value;
            for (let entityKey in rawState.entityMap) {
                if (rawState.entityMap[entityKey].type === TextMergeConstants.MERGE_TEXT_ENTITY_TYPE) {
                    if (subContext) {
                        let fieldpath = rawState.entityMap[entityKey].data.fieldpath;
                        let valueTestResult = subContext.findItem(fieldpath);
                        if (!valueTestResult) {
                            valueTestResult = new TextMergeValueTestResult(fieldpath);
                            subContext.addTestResultItem(valueTestResult);
                            try {
                                let res = DataUtilities.get(data, fieldpath);
                                valueTestResult.result = res;
                                if (!res) {
                                    throw new Error(`"${fieldpath}" is missing`);
                                }
                                else {
                                    subContext.addLogItem(new EventLog(`Got value "${res}" from ${fieldpath}`));
                                }
                            }
                            catch (e) {
                                valueTestResult.isError = true;
                                valueTestResult.result = `"${fieldpath}" is missing`;
                                subContext.addLogItem(new EventLog(`Error in getting value from ${fieldpath} [${e.message}]`));
                            }
                        }
                    }
                    rawState.entityMap[entityKey].data = Object.assign(Object.assign({}, rawState.entityMap[entityKey].data), { onUpdateValue: (fieldpath, newValue) => { }, showModalWithEntity: (entity) => { }, isValidField: this.isValidField });
                }
            }
            let editorState = EditorState.createWithContent(convertFromRaw(rawState));
            result = TextMergeUtility.MergeToHTML(editorState, data);
            if (this.outputType === XTextMergeExportType.TEXT) {
                const turndownService = new TurndownService();
                result = turndownService.turndown(result);
            }
        }
        if (subContext) {
            subContext.addLogItem(new EventLog(`XTextMerge: end evaluating Text Merge with result [${result}]`));
            subContext.result = result;
        }
        return result;
    }
    getEntityType(nodeName, element) {
        if (nodeName === "span") {
            try {
                const fieldpath = element.getAttribute("data-fieldpath");
                if (!fieldpath)
                    return undefined;
                const fieldstr = element.getAttribute("data-field");
                const field = fieldstr ? JSON.parse(fieldstr) : new UndefinedDataDefinition();
                return {
                    type: TextMergeConstants.MERGE_TEXT_ENTITY_TYPE,
                    mutability: "IMMUTABLE",
                    data: {
                        fieldpath,
                        field,
                    },
                };
            }
            catch (e) { }
        }
        return undefined;
    }
    getStorageData() {
        let data = super.getStorageData();
        Reflect.set(data, '_id', this._id);
        Reflect.set(data, 'value', this.value);
        Reflect.set(data, 'outputType', this.outputType);
        return data;
    }
    setStorageData(data) {
        super.setStorageData(data);
        this._id = Reflect.get(data, '_id');
        this.value = Reflect.get(data, 'value');
        this.outputType = Reflect.get(data, 'outputType');
    }
    getDesignValidationIssues() {
        let issues = [];
        for (let entityKey in this.value.entityMap) {
            if (this.value.entityMap[entityKey].type === TextMergeConstants.MERGE_TEXT_ENTITY_TYPE) {
                let fieldpath = this.value.entityMap[entityKey].data.fieldpath;
                try {
                    let field = DataUtilities.getFieldFromDataDefinitionByProperty(this.getInputDefinition().fields, fieldpath, 'name');
                    if (!field) {
                        throw new Error(`can not find field by path [${fieldpath}]`);
                    }
                    if (field.list) {
                        issues.push(new ValidationIssue(`[${fieldpath}] is list`));
                    }
                    if (field instanceof ObjectDataDefinition) {
                        issues.push(new ValidationIssue(`[${fieldpath}] is object`));
                    }
                }
                catch (e) {
                    issues.push(new ValidationIssue(`[${fieldpath}] is invalid`));
                }
            }
        }
        return issues;
    }
}
//# sourceMappingURL=XTextMergeDefinition.js.map