import {
    CircularTextInputElement,
    Condition,
    CustomizationOptions,
    DropdownOption,
    DropdownValue,
    DynamicImageElement,
    ImagePlaceHolderElement,
    ImageUploadOption,
    SwatchOption,
    SwatchValue,
    Template,
    TextInputElement,
    TextInputOption,
    VectorElement
} from "./types";
import axios from 'axios';
import {
    getRenderConfigImage,
    getRenderConfigTextBox,
    getRenderConfigTextBoxCircular,
    getRenderConfigVectorEps,
    isNumeric,
} from "./helper";

type IOption = SwatchOption | DropdownOption | ImageUploadOption | TextInputOption;
type IElement = DynamicImageElement | TextInputElement | CircularTextInputElement | ImagePlaceHolderElement | VectorElement;

class Customization {
    private template: Template;
    private options: IOption[];
    private readonly breadcrumbs: {
        id: number;
        name: string;
        slug: string,
        _lft: number,
        _rgt: number,
        url: string
    }[];
    private readonly baseUrl: string;
    private LibCaching = {} as { [key: string]: string };
    private groupId: string | number | undefined = undefined;
    private showElementIds: (string | number)[] = [];
    private hideElementIds: (string | number)[] = [];
    private selectedGroups = [] as { id: string; uuid: string, position: number }[];

    constructor(customizationOptions: CustomizationOptions) {
        this.template = customizationOptions.template;
        this.options = customizationOptions.options;
        this.baseUrl = customizationOptions.baseUrl;
        this.breadcrumbs = customizationOptions.breadcrumbs;
        this.buildOptionSet();
    }

    getTemplate(): Template {
        return this.template;
    }

    getOptions(): IOption[] {
        return this.options;
    }

    setTemplate(template: Template): void {
        this.template = template;
    }

    setOptions(options: IOption[]): void {
        this.options = options;
    }

    async selectOptionValue(option: IOption, value: SwatchValue | DropdownValue): Promise<void> {
        this.buildOptionSet();
        if (this.isChangeTemplateOption(option as SwatchOption | DropdownOption)) {
            // fetch and set new template
            const templateId = value.templateId;
            const newTemplate = await fetch(`${this.baseUrl}/template/${templateId}`);
            const templateData = await newTemplate.json();
            if (templateData) {
                this.template = templateData.result;
            } else {
                throw new Error('Template not found');
            }
        }

        this.options.forEach((option) => {
            if (option.isShow) {
                if (option.type == 'swatch' || option.type == 'dropdown') {
                    this.changeSwatchOrDropdownValue(option as SwatchOption | DropdownOption);
                } else if (option.type == 'text-input') {
                    this.changeTextInputValue(option as TextInputOption);
                } else if (option.type == 'image-upload') {
                    this.changeImageUploadValue(option as ImageUploadOption);
                }
            }
        });

        // fetch customily library
        await this.fetchCustomilyLibrary();
        let elements = this.template.elements;
        for (const element of elements) {
            if ("images" in element.config && element.config.images.length > 0 && element.config.imageId && !element.config.libraryId) {
                const image = element.config.images.find(item => item.order == element.config.imageId);
                if (image) {
                    element.config.imageUrl = image.value;
                }
            }

            if ("fonts" in element.config && element.config.fonts.length > 0 && element.config.fontId && !element.config.colorLibraryId) {
                const font = element.config.fonts.find(item => item.order == element.config.fontId);
                if (font) {
                    element.config.textConfig.font = font.value;
                }
            }

            if ("colors" in element.config && element.config.colors.length > 0 && element.config.colorId && !element.config.fontLibraryId) {
                const color = element.config.colors.find(item => item.order == element.config.colorId);
                if (color) {
                    element.config.textConfig.fill = color.value;
                }
            }

            if ("vectors" in element.config && element.config.vectors.length > 0 && element.config.vectorId && !element.config.libraryId) {
                const vector = element.config.vectors.find(item => item.order == element.config.vectorId);
                if (vector) {
                    element.config.imageUrl = vector.value;
                }
            }
        }

        this.updateVisibleElement();
    }

    private async fetchCustomilyLibrary() {
        let elements = this.template.elements;
        let promises = [];
        for (const element of elements) {
            if ("images" in element.config && !("library" in element.config) && element.config.imageId && element.config.libraryId) {
                const libraryId = element.config.libraryId;
                const position = element.config.imageId;
                const libCacheKey = `${libraryId}-${position}`;
                const endpoint = `https://app.customily.com/api/Libraries/${libraryId}/Elements/Position/${position}`;
                const promise = new Promise<void>((resolve) => {
                    if (this.LibCaching[libCacheKey]) {
                        element.config.imageUrl = this.LibCaching[libCacheKey];

                        return resolve();
                    }

                    axios.get(endpoint).then((response) => {
                        const baseURL = "https://cdn.customily.com";
                        let pathProperty = 'Path';

                        if (response.data && typeof response.data[pathProperty] != 'undefined' && response.data[pathProperty]) {
                            let contentReplace = response.data[pathProperty].startsWith('/') ? '/Content' : 'Content';
                            this.LibCaching[libCacheKey] = `${baseURL}${response.data[pathProperty].replace(contentReplace, '')}`;
                            element.config.imageUrl = this.LibCaching[libCacheKey];

                            return resolve();
                        }

                        return resolve();
                    })
                });
                promises.push(promise);
            }

            if ("colors" in element.config && !("color_library" in element.config) && element.config.colorId && element.config.colorLibraryId) {
                const libraryId = element.config.colorLibraryId;
                const position = element.config.colorId;
                const libCacheKey = `${libraryId}-${position}`;
                const endpoint = `https://app.customily.com/api/Libraries/${libraryId}/Elements/Position/${position}`;
                const promise = new Promise<void>((resolve) => {
                    if (this.LibCaching[libCacheKey]) {
                        if ("textConfig" in element.config) {
                            element.config.textConfig.fill = this.LibCaching[libCacheKey];
                        }

                        return resolve();
                    }

                    axios.get(endpoint).then((response) => {
                        let pathProperty = 'hex';
                        if (response.data && typeof response.data[pathProperty] != 'undefined' && response.data[pathProperty]) {
                            this.LibCaching[libCacheKey] = response.data[pathProperty];
                            if ("textConfig" in element.config) {
                                element.config.textConfig.fill = this.LibCaching[libCacheKey];
                            }

                            return resolve();
                        }

                        return resolve();
                    });
                });
                promises.push(promise);
            }

            if ("fonts" in element.config && !("font_library" in element.config) && element.config.fontId && element.config.fontLibraryId) {
                const libraryId = element.config.fontLibraryId;
                const position = element.config.fontId;
                const libCacheKey = `${libraryId}-${position}`;
                const endpoint = `https://app.customily.com/api/Libraries/${libraryId}/Elements/Position/${position}`;
                const promise = new Promise<void>((resolve) => {
                    if (this.LibCaching[libCacheKey]) {
                        if ("textConfig" in element.config) {
                            element.config.textConfig.font = this.LibCaching[libCacheKey];
                        }

                        return resolve();
                    }

                    axios.get(endpoint).then((response) => {
                        const baseURL = "https://cdn.customily.com";
                        let pathProperty = 'Path';

                        if (response.data && typeof response.data[pathProperty] != 'undefined' && response.data[pathProperty]) {
                            let contentReplace = response.data[pathProperty].startsWith('/') ? '/Content' : 'Content';
                            this.LibCaching[libCacheKey] = `${baseURL}${response.data[pathProperty].replace(contentReplace, '')}`;
                            if ("textConfig" in element.config) {
                                element.config.textConfig.font = this.LibCaching[libCacheKey];
                                element.config.textConfig.fontFamily = 'customFont-' + response.data.fontId;
                                element.config.textConfig.fontFamilyDownload = this.LibCaching[libCacheKey];
                            }

                            return resolve();
                        }

                        return resolve();
                    });
                });
                promises.push(promise);
            }

            if ("vectors" in element.config && !("vector_library" in element.config) && element.config.vectorId && element.config.libraryId) {
                const libraryId = element.config.libraryId;
                const position = element.config.vectorId;
                const libCacheKey = `${libraryId}-${position}`;
                const endpoint = `https://app.customily.com/api/Libraries/${libraryId}/Elements/Position/${position}`;
                const promise = new Promise<void>((resolve) => {
                    if (this.LibCaching[libCacheKey]) {
                        element.config.imageUrl = this.LibCaching[libCacheKey];

                        return resolve();
                    }

                    axios.get(endpoint).then((response) => {
                        const baseURL = "https://cdn.customily.com";
                        let pathProperty = 'svgPath';

                        if (response.data && typeof response.data[pathProperty] != 'undefined' && response.data[pathProperty]) {
                            let contentReplace = response.data[pathProperty].startsWith('/') ? '/Content' : 'Content';
                            this.LibCaching[libCacheKey] = `${baseURL}${response.data[pathProperty].replace(contentReplace, '')}`;
                            element.config.imageUrl = this.LibCaching[libCacheKey];

                            return resolve();
                        }

                        return resolve();
                    });
                });
                promises.push(promise);
            }
        }

        await Promise.all(promises);
    }

    private buildOptionSet() {
        // set currentValue for selected value
        this.options.forEach((option: IOption) => {
            if (option.type == 'swatch' || option.type == 'dropdown') {
                let selectedValue;
                if ("dropdownValues" in option) {
                    selectedValue = option.dropdownValues?.find((value: DropdownValue) => value.selected);
                } else if ("swatchValues" in option) {
                    selectedValue = option.swatchValues?.find((value: SwatchValue) => value.selected);
                }

                // @ts-ignore
                if (selectedValue && !Object.hasOwnProperty.call(option, 'currentValue')) {
                    option.currentValue = selectedValue.id;
                }

                if (selectedValue && Object.hasOwnProperty.call(selectedValue, 'groupId')) {
                    this.groupId = selectedValue.groupId;
                }
            }
        });
        // build isShow for option
        this.options.forEach((option: IOption) => {
            option.isShow = this.isShowOption(this.options, option);
            if (option.isShow) {
                if (this.isExcessiveSizeOption(option) || this.isExcessiveColorOption(option)) {
                    option.hideVisually = true;
                }
            }
        });

        // re-check isShow option
        this.options.forEach((optionItem: IOption) => {
            if (optionItem.isShow) {
                let conditionValues = [] as { value: boolean; combinationOperator: string }[];
                if (optionItem.conditions && optionItem.conditions.length > 0) {
                    optionItem.conditions.forEach((condition: Condition) => {
                        const watchOptionId = condition.watchOptionId;
                        const watchOption = this.options.find(item => item.id == watchOptionId);

                        if (watchOption && watchOption.isShow || !watchOption) {
                            conditionValues.push({
                                value: true,
                                combinationOperator: condition.combinationOperator
                            })
                        } else {
                            conditionValues.push({
                                value: false,
                                combinationOperator: condition.combinationOperator
                            })
                        }
                    });


                    let finalCondition = true;
                    if (conditionValues.length) {
                        finalCondition = conditionValues.reduce(function(preCondition, condition) {
                            if (condition.combinationOperator === 'or') {
                                return preCondition || condition.value;
                            } else {
                                return preCondition && condition.value;
                            }
                        }, false);

                        if (conditionValues.length == 1) finalCondition = conditionValues[0].value;
                    }

                    optionItem.isShow = finalCondition;
                }
            }
        });
    }

    private isShowOption(options: IOption[], option: IOption): boolean {
        let conditions = option.conditions;
        if (conditions && conditions.length > 0) {
            let conditionValues = [];
            for (const condition of conditions) {
                if (condition.watchOptionId) {
                    let watchOptionIndex = options.findIndex(item => item.id === condition.watchOptionId);
                    if (watchOptionIndex >= 0) {
                        let watchOption = options[watchOptionIndex];
                        // @ts-ignore
                        if ((Array.isArray(condition.desiredValue) && condition.desiredValue.includes(watchOption.currentValue)) ||
                            condition.desiredValue == watchOption.currentValue ||
                            // @ts-ignore
                            (Array.isArray(condition.desiredValue) && condition.desiredValue.includes(-1))
                        ) {
                            conditionValues.push({
                                value: true,
                                combinationOperator: condition.combinationOperator,
                            });
                        } else {
                            conditionValues.push({
                                value: false,
                                combinationOperator: condition.combinationOperator,
                            })
                        }
                    } else {
                        // true if watchOptionId not found
                        conditionValues.push({
                            value: true,
                            combinationOperator: condition.combinationOperator,
                        });
                    }
                }
            }

            let finalCondition = true;
            if (conditionValues.length) {
                finalCondition = conditionValues.reduce(function(preCondition, condition) {
                    if (condition.combinationOperator === 'or') {
                        return preCondition || condition.value;
                    } else {
                        return preCondition && condition.value;
                    }
                }, false);

                if (conditionValues.length == 1) finalCondition = conditionValues[0].value;

            }

            return finalCondition;
        }

        return true;
    }

    private isExcessiveSizeOption(obj: IOption) {
        const isLabelSize = obj.label && obj.label.toLowerCase().includes('size');
        const sizeValues = ['S', 'M', 'L', 'XL', '2XL', '3XL', '4XL'];
        let valuesToCheck;
        if ('dropdownValues' in obj) {
            valuesToCheck = obj.dropdownValues;
        } else if ('swatchValues' in obj) {
            valuesToCheck = obj.swatchValues;
        }

        const areValuesSizes = valuesToCheck && valuesToCheck.some(value =>
            sizeValues.includes(value.valueName)
        );

        return isLabelSize && areValuesSizes;
    }

    private isExcessiveColorOption(obj: IOption) {
        const isLabelColor = obj.label && obj.label.toLowerCase().includes('color');
        const validateLabelColors = [
            'Shirt\'s Color', 'Hoodie\'s Color', 'Hoodie Color',
            'Sweatshirt\'s Color', 'Sweatshirt Color', 'Tank Top\'s Color', 'Tank Top Color',
            'T-Shirt\'s Color', 'T-Shirt Color', 'Polo\'s Color', 'Polo Color', 'Tee Color'
        ]

        let isTShirt = false;
        if (this.breadcrumbs && this.breadcrumbs.length > 2 && this.breadcrumbs[2].id == 7) {
            isTShirt = true;
        }

        let isValidLabelColor: boolean;

        if (isTShirt) {
            isValidLabelColor = validateLabelColors.some(label => obj.label.toLowerCase().includes(label.toLowerCase()));
        } else {
            isValidLabelColor = validateLabelColors.includes(obj.label);
        }

        return isLabelColor && isValidLabelColor;
    }

    private changeSwatchOrDropdownValue(option: SwatchOption | DropdownOption): void {
        let values;
        if ("dropdownValues" in option) {
            values = option.dropdownValues;
        }

        if ("swatchValues" in option) {
            values = option.swatchValues;
        }

        if (!values) {
            return;
        }

        let value = values.find((item: SwatchValue | DropdownValue) => item.id === option.currentValue);
        if (!value) {
            value = values.find((item: SwatchValue | DropdownValue) => item.selected);
        }

        if (!value) {
            return;
        }

        if (value.groupId) {
            this.groupId = value.groupId;
        }

        let functionItems = option.functionItems;
        if (!functionItems) {
            return;
        }

        for (let functionItem of functionItems) {
            let elementId = functionItem.elementId;
            // find element in template
            let element = this.template.elements.find(
                item => item.elementId == elementId
            );
            if (!element) {
                continue;
            }

            if (functionItem.type == 'dynamic-image') {
                let valueId = this.getValueId(value);
                let dynamicImageElement: DynamicImageElement = element as DynamicImageElement;
                if (dynamicImageElement.config.images?.length && ("library" in dynamicImageElement.config)) {
                    let image = dynamicImageElement.config.images?.find(
                        item => item.order == valueId
                    );
                    if (image) {
                        dynamicImageElement.config.imageUrl = image.value;
                        dynamicImageElement.config.imageId = valueId;
                    }
                } else {
                    dynamicImageElement.config.imageId = valueId;

                }

                // check if element has child elements
                if (dynamicImageElement.config.childElementIds?.length) {
                    for (let childElementId of dynamicImageElement.config.childElementIds) {
                        let childElement = this.template.elements.find(
                            item => item.elementId == childElementId
                        ) as DynamicImageElement;

                        if (childElement) {
                            childElement.config.imageId = valueId;
                            if (dynamicImageElement.config.imageUrl) {
                                childElement.config.imageUrl = dynamicImageElement.config.imageUrl;
                                this.setElement(childElement, childElementId)
                            }
                        }
                    }
                }

                this.setElement(dynamicImageElement, elementId);
            } else if (functionItem.type == 'font-type') {
                let valueId = this.getValueId(value);
                let textInputElement = element as TextInputElement;
                if (textInputElement.config.fonts) {
                    let font = textInputElement.config.fonts.find(
                        item => item.order == valueId
                    );
                    if (font) {
                        textInputElement.config.textConfig.font = font.value;
                        textInputElement.config.fontId = valueId;
                    }
                } else {
                    textInputElement.config.fontId = valueId;
                }

                // check if element has child elements
                if (textInputElement.config.childElementIds?.length) {
                    for (let childElementId of textInputElement.config.childElementIds) {
                        let childElement = this.template.elements.find(
                            item => item.elementId == childElementId
                        ) as TextInputElement;

                        if (childElement) {
                            childElement.config.fontId = valueId;
                            if (textInputElement.config.textConfig.font) {
                                childElement.config.textConfig.font = textInputElement.config.textConfig.font;
                                this.setElement(childElement, childElementId)
                            }

                        }
                    }
                }

                this.setElement(textInputElement, elementId);
            } else if (functionItem.type == 'text-color') {
                let valueId = this.getValueId(value);
                let textInputElement = element as TextInputElement;
                if (textInputElement.config.colors) {
                    let color = textInputElement.config.colors.find(
                        item => item.order == valueId
                    );
                    if (color) {
                        textInputElement.config.textConfig.fill = color.value;
                        textInputElement.config.colorId = valueId;
                    }
                } else {
                    textInputElement.config.colorId = valueId;
                }

                // check if element has child elements
                if (textInputElement.config.childElementIds?.length) {
                    for (let childElementId of textInputElement.config.childElementIds) {
                        let childElement = this.template.elements.find(
                            item => item.elementId == childElementId
                        ) as TextInputElement;

                        if (childElement) {
                            if (textInputElement.config.textConfig.fill) {
                                childElement.config.textConfig.fill = textInputElement.config.textConfig.fill
                            }

                            childElement.config.colorId = valueId;
                            this.setElement(childElement, childElementId)
                        }
                    }
                }

                this.setElement(textInputElement, elementId);
            } else if (functionItem.type === 'vector') {
                let valueId = this.getValueId(value);
                let vectorElement: VectorElement = element as VectorElement;
                if (vectorElement.config.vectors?.length) {
                    let image = vectorElement.config.vectors?.find(
                        item => item.order == valueId
                    );
                    if (image) {
                        vectorElement.config.imageUrl = image.value;
                        vectorElement.config.vectorId = valueId;
                    }
                } else {
                    vectorElement.config.vectorId = valueId;
                }

                // check if element has child elements
                if (vectorElement.config.childElementIds?.length) {
                    for (let childElementId of vectorElement.config.childElementIds) {
                        let childElement = this.template.elements.find(
                            item => item.elementId == childElementId
                        ) as DynamicImageElement;

                        if (childElement) {
                            childElement.config.imageId = valueId;
                            if (vectorElement.config.imageUrl) {
                                childElement.config.imageUrl = vectorElement.config.imageUrl;
                                this.setElement(childElement, childElementId);
                            }
                        }
                    }
                }

                this.setElement(element, elementId);
            }
        }

    }

    private changeImageUploadValue(option: ImageUploadOption) :void {
        if (!option.fileUploadImageId || typeof option.currentValue === 'undefined') {
            return;
        }

        const imageUrl = option.currentValue.toString();
        let uploadImageElementId = option.fileUploadImageId;
        let uploadImageElement = this.template.elements.find(
            item => item.elementId == uploadImageElementId
        ) as DynamicImageElement | ImagePlaceHolderElement;
        if (uploadImageElement) {
            uploadImageElement.config.imageUrl = imageUrl;
            // check if element has child elements
            if (uploadImageElement.config.childElementIds?.length) {
                for (let childElementId of uploadImageElement.config.childElementIds) {
                    let childElement = this.template.elements.find(
                        item => item.elementId == childElementId
                    ) as DynamicImageElement | ImagePlaceHolderElement;

                    if (childElement) {
                        childElement.config.imageUrl = imageUrl;
                        // set element to template.elements
                        let index = this.template.elements.findIndex(
                            item => item.elementId == childElementId
                        );
                        if (index >= 0) {
                            this.template.elements[index] = childElement;
                        }
                    }
                }
            }

            // set element to template.elements
            let index = this.template.elements.findIndex(
                item => item.elementId == uploadImageElementId
            );
            if (index >= 0) {
                this.template.elements[index] = uploadImageElement;
            }
        }
    }

    private changeTextInputValue(option: TextInputOption): void {
        if (typeof option.currentValue === 'undefined') {
            return;
        }

        let text = option.currentValue.toString();
        let functionItems = option.functionItems;
        if (!functionItems) {
            return;
        }

        for (let functionItem of functionItems) {
            let elementId = functionItem.elementId;
            // find element in template
            let element = this.template.elements.find(
                item => item.elementId == elementId
            );
            if (!element) {
                continue;
            }

            if (functionItem.type == 'text-input') {
                let textInputElement = element as TextInputElement;
                textInputElement.config.textConfig.text = text;

                // check if element has child elements
                if (textInputElement.config.childElementIds?.length) {
                    for (let childElementId of textInputElement.config.childElementIds) {
                        let childElement = this.template.elements.find(
                            item => item.elementId == childElementId
                        ) as TextInputElement;

                        if (childElement) {
                            childElement.config.textConfig.text = text;
                            // set element to template.elements
                            let index = this.template.elements.findIndex(
                                item => item.elementId == childElementId
                            );
                            if (index >= 0) {
                                this.template.elements[index] = childElement;
                            }
                        }
                    }
                }

                // set element to template.elements
                let index = this.template.elements.findIndex(
                    item => item.elementId == elementId
                );
                if (index >= 0) {
                    this.template.elements[index] = element;
                }
            }
        }
    }

    private isChangeTemplateOption(option: SwatchOption | DropdownOption): boolean {
        let functionItems = option.functionItems;
        if (!functionItems) {
            return false;
        }

        for (let functionItem of functionItems) {
            if (functionItem.type == 'change-template') {
                return true;
            }
        }

        return false;
    }

    private getValueId(value: SwatchValue | DropdownValue): number | string {
        let valueId: number | string = -1;
        if (value.imageId) {
            valueId = value.imageId;
        } else if (value.id) {
            if (typeof value.id === "string") {
                valueId = parseInt(value.id) + 1;
            } else {
                valueId = value.id + 1;
            }
        } else if (typeof value.value != 'undefined' && isNumeric(value.value)) {
            if (typeof value.value === "string") {
                valueId = parseInt(value.value) + 1;
            } else {
                valueId = value.value + 1;
            }
        }
        return valueId;
    }

    private setElement (element: IElement, elementId: string | number | undefined) {
        // set element to template.elements
        if (typeof elementId !== 'undefined') {
            let index = this.template.elements.findIndex(
                item => item.elementId == elementId
            );
            if (index >= 0) {
                this.template.elements[index] = element;
            }
        }
    }

    private updateVisibleElement() {
        if (!this.template) {
            return;
        }

        this.buildShowHideElements();
        const VISIBILITY = {show: 1, hide: 0};
        for (const element of this.template.elements) {
            let opacity = VISIBILITY.hide;
            element.isShow = false;

            if (this.showElementIds.includes(element.elementId) || this.showElementIds.includes(element.elementId.toString())) {
                opacity = VISIBILITY.show;
                element.isShow = true;
            } else if (!this.hideElementIds.includes(element.elementId) && !this.hideElementIds.includes(element.elementId.toString())) {
                opacity = VISIBILITY.show;
            }

            // check show hide by group
            if (element.groupId && typeof this.selectedGroups != 'undefined') {
                const groupIds = this.selectedGroups.map((g) => {
                    return g.id
                });
                if (!groupIds.includes(element.groupId)) {
                    opacity = VISIBILITY.hide;
                    element.isShow = false;
                }
            }

            element.opacity = opacity;
        }
    }

    private buildShowHideElements() {
        let showElementIds: (string | number)[] = [];
        let hideElementIds: (string | number)[] = [];
        this.setSelectedGroups();
        for (const thisOption of this.options) {
            // check show / hide on canvas
            // upload image id
            if ("fileUploadImageId" in thisOption && thisOption.fileUploadImageId) {

                const element = this.template.elements.find(function(element: IElement) {
                    return element.elementId == thisOption.fileUploadImageId;
                });

                if (element) {
                    this.addShowConditionArray(element, thisOption, showElementIds, hideElementIds);
                }
            }

            // function items
            if (thisOption.functionItems && thisOption.functionItems.length) {
                // function items
                for (let j = 0; j < thisOption.functionItems.length; j++) {
                    const elementId = thisOption.functionItems[j].elementId;
                    const element = this.template.elements.find(function(element) {
                        return element.elementId == elementId;
                    });

                    if (element) {
                        if (thisOption.functionItems[j].type == 'text' && element.type == 'dynamic_image') continue;
                        this.addShowConditionArray(element, thisOption, showElementIds, hideElementIds);
                    }
                }
            }
        }

        // convert to unique array
        showElementIds = showElementIds.filter(function (value, index, self) {
            return self.indexOf(value) === index;
        });
        hideElementIds = hideElementIds.filter(function (value, index, self) {
            return self.indexOf(value) === index;
        });

        this.showElementIds = showElementIds;
        this.hideElementIds = hideElementIds;
    }

    private setSelectedGroups() {
        const groups = [];
        if (typeof this.template.groups != 'undefined' && this.template.groups) {
            this.template.groups = JSON.parse(this.template.groups);
            // @ts-ignore
            for (let i = 0; i < this.template.groups.length; i++) {
                // @ts-ignore
                const group = this.template.groups[i];
                // @ts-ignore
                if (this.groupId && parseInt(this.groupId) == parseInt(group.position)) {
                    groups.push(group);
                }
            }
        }

        if (groups.length) {
            // @ts-ignore
            this.selectedGroups = groups;
        }
    }

    private addShowConditionArray = (element: IElement, option: IOption, showElementIds: (string | number)[], hideElementIds: (string | number)[]) => {
        const childElementIds = element.childElementIds ?? [];
        let emptyValues = true;
        if ("swatchValues" in option) {
            emptyValues = (option.swatchValues && !option.swatchValues.length);
        }

        if ("dropdownValues" in option) {
            emptyValues = (option.dropdownValues && !option.dropdownValues.length);
        }


        if ((option.isShow || typeof option.hideVisually == 'undefined') && !showElementIds.includes(element.elementId)  && !emptyValues) {
            showElementIds.push(element.elementId);
            if (childElementIds && childElementIds.length) {
                for (let k = 0; k < childElementIds.length; k++) {
                    showElementIds.push(childElementIds[k]);
                }
            }
        } else {
            hideElementIds.push(element.elementId);
            if (childElementIds && childElementIds.length) {
                for (let k = 0; k < childElementIds.length; k++) {
                    hideElementIds.push(childElementIds[k]);
                }
            }
        }
    }

    getFabricConfig(element: IElement) {
        switch (element.type) {
            case 'text_box_circular':
                return getRenderConfigTextBoxCircular(element as CircularTextInputElement);
            case 'text_box':
                return getRenderConfigTextBox(element as TextInputElement);
            case 'dynamic_image':
            case 'image_placeholder':
                return getRenderConfigImage(element as DynamicImageElement);
            case 'vector_eps':
                return getRenderConfigVectorEps(element as VectorElement);
        }
    }
}

export default Customization;