// @ts-nocheck

import _ from 'lodash';
import { getCdn } from "./helper";

type TeeinblueInitOptions = {
    campaignProductIndex?: number;
    campaignMockupId?: string | number;
    mockupId?: string | number;
    printareaId?: string | number;
    templateId?: string | number;
    state?: any;
};

class CustomizationTeeInBlue
{
    private campaign;
    private options: TeeinblueInitOptions;
    private campaignProduct;
    private campaignMockupId;
    private mockupId;
    private printareaId;
    private campaignMockup;
    private template;
    private artworks = [];
    private artwork;
    private customFontFamilies = {};
    private googleFontFamilies = {};
    private designLayers = [];
    private templateOptions = [];
    private layerOptions = [];
    private templateLayers = [];
    private layerById = {};
    private clipartCategoryById = {};
    private groupedClipartsByParentId = {};
    private printAreaIds = [];
    private printAreas = [];

    constructor(campaign, options: TeeinblueInitOptions = {})
    {
        this.campaign = _.cloneDeep(campaign?.result || campaign || {});
        this.options = options || {};

        this.prepareCampaignLookups();
        this.selectCampaignProduct();
        this.selectCampaignMockup();
        this.initPrintAreas();
        this.loadArtworks();
        this.applyInitialState(options.state);
        this.rebuild();
    }

    private rebuild()
    {
        this.prepareTemplateLookups();
        this.bindDefaultLayersValue();
        this.buildOptionsList();
        this.buildDesignLayers();
        this.buildPrintAreas();
    }

    private prepareCampaignLookups()
    {
        const categories = this.campaign.clipart_categories || [];
        this.clipartCategoryById = {};
        this.groupedClipartsByParentId = {};

        for (let i = 0; i < categories.length; i++) {
            const category = categories[i];
            this.clipartCategoryById[category.id] = category;

            if (category.parent_id) {
                if (!this.groupedClipartsByParentId[category.parent_id]) {
                    this.groupedClipartsByParentId[category.parent_id] = [];
                }
                this.groupedClipartsByParentId[category.parent_id].push(category);
            }
        }
    }

    private selectCampaignProduct()
    {
        const products = this.campaign.campaign_products || [];
        this.campaignProduct = products[this.options.campaignProductIndex || 0] || products[0] || null;
    }

    private selectCampaignMockup()
    {
        if (!this.campaignProduct) return;

        const campaignMockups = this.campaignProduct.campaign_mockups || [];
        const campaignVariants = this.campaignProduct.campaign_variants || [];

        this.campaignMockupId = this.options.campaignMockupId;
        this.mockupId = this.options.mockupId;
        this.printareaId = this.options.printareaId;

        if (!this.campaignMockupId && !this.mockupId && campaignVariants.length) {
            for (let i = 0; i < campaignVariants.length; i++) {
                const campaignVariant = campaignVariants[i];

                if (campaignVariant.campaign_mockup_id) {
                    this.campaignMockupId = campaignVariant.campaign_mockup_id;
                    break;
                }

                if (campaignVariant.variant?.mockup_id && campaignVariant.variant?.printarea_id) {
                    this.mockupId = campaignVariant.variant.mockup_id;
                    this.printareaId = campaignVariant.variant.printarea_id;
                    break;
                }
            }
        }

        if (this.mockupId && this.printareaId) {
            this.campaignMockup = campaignMockups.find(cpm => cpm.mockup_id == this.mockupId);
        }

        if (!this.campaignMockup && this.campaignMockupId) {
            this.campaignMockup = campaignMockups.find(cpm => cpm.id == this.campaignMockupId);
        }

        if (!this.campaignMockup && campaignMockups.length == 1) {
            this.campaignMockup = campaignMockups[0];
        }

        if (!this.campaignMockup) {
            this.campaignMockup = campaignMockups.find(cpm => cpm.mockup_id != null || cpm.old_campaign_mockup_id != null);
        }

        if (!this.campaignMockup) {
            this.campaignMockup = campaignMockups.find(cpm => {
                return (cpm.layers || []).find(layer => layer.printarea_id);
            }) || campaignMockups[0] || null;
        }

        if (this.campaignMockup?.layers) {
            this.campaignMockup.layers = this.campaignMockup.layers.map(layer => this.normalizeMockupLayer(layer));
        }
    }

    private normalizeMockupLayer(layer)
    {
        const normalized = _.cloneDeep(layer);
        if (normalized.url) normalized.url = getCdn(normalized.url);
        if (normalized.masked_image) normalized.masked_image = getCdn(normalized.masked_image);
        return normalized;
    }

    private initPrintAreas()
    {
        this.printAreaIds = [];

        const layers = this.campaignMockup?.layers || [];
        for (let i = 0; i < layers.length; i++) {
            const layer = layers[i];
            if (layer.visible === false) continue;
            if (!layer.url && layer.printarea_id) this.printAreaIds.push(layer.id);
        }
    }

    private loadArtworks()
    {
        const artworkCampaigns = this.findActiveCampaignArtwork();
        const artworkIds = artworkCampaigns.map(pa => pa.artwork_id);
        const activeArtworks = (this.campaign.artworks || []).filter(artwork => artworkIds.includes(artwork.id));

        this.artworks = activeArtworks.length ? activeArtworks : (this.campaign.artworks || []);
        if (!this.artworks.length) return;

        let selectedArtwork = null;
        let selectedTemplate = null;

        if (this.options.templateId) {
            for (let i = 0; i < this.artworks.length; i++) {
                const artwork = this.artworks[i];
                const template = (artwork.data || []).find(item => item.id == this.options.templateId);
                if (template) {
                    selectedArtwork = artwork;
                    selectedTemplate = template;
                    break;
                }
            }
        }

        // Auto-select template chỉ khi có duy nhất 1 artwork.
        // Nếu có nhiều artwork và user chưa chọn (không truyền templateId), validate() sẽ yêu cầu user chọn.
        if (!selectedTemplate && this.artworks.length === 1) {
            selectedArtwork = this.artworks[0];
            selectedTemplate = selectedArtwork.data?.[0] || null;
        }

        if (selectedArtwork && selectedTemplate) {
            this.setActiveArtworkTemplate(selectedArtwork, selectedTemplate);
        }
    }

    private findActiveCampaignArtwork()
    {
        const campaignArtworks = this.campaign.campaign_artworks || [];

        if (this.printareaId) {
            const foundArtwork = campaignArtworks.filter(cp => cp.printarea_id == this.printareaId);
            if (foundArtwork.length) return foundArtwork;
        }

        const printareaIds = [];
        const mockupLayers = this.campaignMockup?.layers || [];
        for (let i = 0; i < mockupLayers.length; i++) {
            if (mockupLayers[i].printarea_id) printareaIds.push(mockupLayers[i].printarea_id);
        }

        const matched = campaignArtworks.filter(cp => printareaIds.includes(cp.printarea_id));
        return matched.length ? matched : campaignArtworks;
    }

    private setActiveArtworkTemplate(artwork, template)
    {
        if (!artwork || !template) return;

        this.artwork = artwork;
        this.template = template;
        this.templateLayers = _.cloneDeep(template.layers || []);

        // Lưu base position để applyReposition reset đúng, tránh cộng dồn offset qua nhiều lần đổi option.
        for (let i = 0; i < this.templateLayers.length; i++) {
            const layer = this.templateLayers[i];
            layer._baseTop = layer.top || 0;
            layer._baseLeft = layer.left || 0;
        }

        for (let i = 0; i < (artwork.data || []).length; i++) {
            artwork.data[i].active = artwork.data[i].id == template.id;
        }
    }

    private prepareTemplateLookups()
    {
        this.layerById = {};
        for (let i = 0; i < this.templateLayers.length; i++) {
            this.layerById[this.templateLayers[i].id] = this.templateLayers[i];
        }
    }

    // Tạo bản shallow-clone cho từng templateLayer trước khi mutator chạy.
    // Giữ cho ref cũ (đang được snapshot trước đó nắm) không bị thay đổi → React/RN
    // memo/PureComponent thấy ref mới ở các layer được sửa và re-render đúng.
    private cloneTemplateLayers()
    {
        this.templateLayers = this.templateLayers.map(layer => ({ ...layer }));
        this.prepareTemplateLookups();
    }

    private bindDefaultLayersValue()
    {
        for (let i = 0; i < this.templateLayers.length; i++) {
            const layer = this.templateLayers[i];

            if (typeof layer.form_visibility != 'undefined' && typeof layer.form_visibility_value == 'undefined') {
                layer.form_visibility_value = layer.form_visibility;
            }

            if (typeof layer.value != 'undefined' || typeof layer.show_value != 'undefined') continue;

            if (layer.default_value) {
                layer.show_value = layer.default_value;
                let value = layer.default_value;

                if (layer.form_type == 'grouped_clipart') {
                    const groupedCliparts = this.getGroupedClipart(layer);
                    for (let j = 0; j < groupedCliparts.length; j++) {
                        const elementClipart = groupedCliparts[j];
                        const optionValue = (elementClipart.options || []).find(opt => {
                            return opt.url == layer.default_value || getCdn(opt.url) == getCdn(layer.default_value);
                        });
                        if (optionValue) {
                            value = elementClipart.id;
                            elementClipart.show_value = optionValue.url;
                        } else if (elementClipart.options?.[0]) {
                            elementClipart.show_value = elementClipart.options[0].url;
                        }
                    }
                }

                layer.value = value;
            } else if (layer.url) {
                layer.show_value = layer.url;
            }
        }
    }

    private applyInitialState(state)
    {
        if (!state) return;

        if (state.templateId) this.selectTemplate(state.templateId, false);
        if (state.layers) {
            for (let i = 0; i < this.templateLayers.length; i++) {
                const layer = this.templateLayers[i];
                const savedLayer = state.layers[layer.id];
                if (!savedLayer) continue;

                if (savedLayer.value !== undefined) layer.value = savedLayer.value;
                if (savedLayer.show_value !== undefined) layer.show_value = savedLayer.show_value;
                if (savedLayer.form_visibility_value !== undefined) layer.form_visibility_value = savedLayer.form_visibility_value;
                if (savedLayer.selected_name !== undefined) layer.selected_name = savedLayer.selected_name;
                if (savedLayer.optionItem !== undefined) layer.optionItem = savedLayer.optionItem;
            }
        }
    }

    private buildOptionsList()
    {
        this.templateOptions = this.buildTemplateOptions();
        this.layerOptions = this.buildLayerOptions();
    }

    private buildTemplateOptions()
    {
        return this.artworks.map(artwork => {
            const optionValues = (artwork.data || []).map(template => ({
                id: template.id,
                name: template.name,
                title: template.title || template.name,
                url: template.url ? getCdn(template.url) : null,
                thumbnail: template.thumbnail ? getCdn(template.thumbnail) : (template.url ? getCdn(template.url) : null),
                active: this.template?.id == template.id,
                artworkId: artwork.id,
            }));

            return {
                artworkId: artwork.id,
                label: artwork.template_settings?.label || artwork.name,
                optionValues,
                values: optionValues,
            };
        });
    }

    private buildLayerOptions()
    {
        const layerOptions = [];
        const positions = this.template?.positions || this.templateLayers.map(layer => layer.id);

        for (let index = 0; index < positions.length; index++) {
            const layer = this.layerById[positions[index]];
            if (!this.shouldRenderOptionLayer(layer)) continue;

            const option = this.normalizeOptionLayer(layer);
            layerOptions.push(option);
        }

        return layerOptions;
    }

    private normalizeOptionLayer(layer)
    {
        const option = _.cloneDeep(layer);
        option.isShow = this.shouldRenderOptionLayer(layer);
        option.input_type = this.getLayerInputType(layer);
        option.option_items = [];

        if (option.type == 'option') {
            option.option_items = this.getAdditionOptions(layer);
        } else if (option.form_type == 'clipart') {
            option.option_items = this.getClipartOptions(layer);
        } else if (option.form_type == 'grouped_clipart') {
            option.option_items = this.getGroupedClipart(layer);
        }

        option.options = option.option_items;
        return option;
    }

    private getLayerInputType(layer)
    {
        if (layer.type == 'text') return 'text';
        if (layer.form_type == 'photo') return 'photo';
        if (layer.form_type == 'grouped_clipart') return 'grouped_clipart';
        if (layer.form_type == 'clipart') return 'clipart';
        if (layer.type == 'option') return 'option';
        return layer.form_type || layer.type;
    }

    private shouldRenderOptionLayer(layer)
    {
        return !!(layer
            && layer.visible
            && layer.form_type != 'static'
            && this.isShowLayer(layer)
            && layer.form_type != 'linked'
            && layer.type != 'group'
            && (layer.form_label || layer.form_type || layer.additional_option));
    }

    private buildDesignLayers()
    {
        this.designLayers = [];
        this.googleFontFamilies = {};
        this.customFontFamilies = {};

        for (let i = 0; i < this.templateLayers.length; i++) {
            const layer = this.templateLayers[i];
            const designLayer = this.toDesignLayer(layer, i);
            if (designLayer) this.designLayers.push(designLayer);
        }
    }

    private toDesignLayer(layer, orderFallback = 0)
    {
        if (!layer || !layer.visible) return null;

        let isShowLayer = this.isShowLayer(layer);
        if (layer.form_visibility && typeof layer.form_visibility_value == 'boolean') {
            isShowLayer = layer.form_visibility_value && isShowLayer;
        } else if (layer.form_visibility_value === false) {
            isShowLayer = false;
        }

        if (!isShowLayer) return null;

        const base = {
            uid: layer.id,
            id: layer.id,
            name: layer.name,
            layerType: layer.type,
            formType: layer.form_type || null,
            s_width: layer.width,
            s_height: layer.height,
            width: layer.width,
            height: layer.height,
            top: layer.top || 0,
            left: layer.left || 0,
            order: layer.order ?? orderFallback,
            angle: layer.rotate || 0,
            rotate: layer.rotate || 0,
            opacity: 1,
            locked: layer.form_type == 'photo' ? false : true,
            value: layer.value,
            show_value: layer.show_value,
            selected_name: layer.selected_name || null,
            linked: layer.linked || null,
            group_id: layer.group_id || null,
        };

        if (layer.url || layer.type == 'clipart') {
            const src = layer.show_value || layer.url;
            if (!src) return null;

            return {
                ...base,
                type: 'image',
                src: getCdn(src),
                url: getCdn(src),
                masked_enable: layer.masked_enable || false,
                masked_url: layer.masked_url ? getCdn(layer.masked_url) : null,
                masked_image: layer.masked_image ? getCdn(layer.masked_image) : null,
            };
        }

        if (layer.type == 'text') {
            const text = this.getLayerText(layer);

            const renderConfig = {
                ...base,
                type: 'text',
                text,
                defaultText: layer.text,
                align: layer.align,
                color: layer.color,
                max_length: layer.max_length,
                typography: layer.typography,
                custom_font: layer.custom_font ? {
                    ...layer.custom_font,
                    url: layer.custom_font.url ? getCdn(String(layer.custom_font.url).replace(/\.(otf|ttf)$/i, '.woff2')) : layer.custom_font.url,
                } : null,
                color_option: layer.color_option,
                stroke_color: layer.stroke_color,
                stroke_width: layer.stroke_width,
                stroke_enabled: layer.stroke_enabled ?? false,
                typography_type: layer.typography_type ?? 'google',
                autoscale_enabled: layer.autoscale_enabled,
                autoscale_max_width: layer.autoscale_max_width,
                form_input_textcase: layer.form_input_textcase ?? null,
                prefix: layer.prefix ?? null,
                suffix: layer.suffix ?? null,
            };

            this.collectFont(renderConfig);
            return renderConfig;
        }

        return null;
    }

    private getLayerText(layer)
    {
        let text = layer.value !== undefined && layer.value !== null ? String(layer.value) : (layer.text || '');
        if (layer.form_input_textcase == 'uppercase') text = text.toUpperCase();
        if (layer.prefix) text = layer.prefix + text;
        if (layer.suffix) text = text + layer.suffix;
        return text;
    }

    private collectFont(layer)
    {
        const typographyType = layer.typography_type ?? 'google';

        if (typographyType == 'google' && layer.typography?.family) {
            if (typeof this.googleFontFamilies[layer.typography.family] == "undefined") {
                this.googleFontFamilies[layer.typography.family] = [];
            }
            if (layer.typography.variant && this.googleFontFamilies[layer.typography.family].indexOf(layer.typography.variant) == -1) {
                this.googleFontFamilies[layer.typography.family].push(layer.typography.variant);
            }
        } else if (typographyType == 'custom' && layer.custom_font?.family) {
            this.customFontFamilies[layer.custom_font.family] = layer.custom_font;
        }
    }

    private buildPrintAreas()
    {
        this.printAreas = [];
        const mockupLayers = this.campaignMockup?.layers || [];

        for (let i = 0; i < mockupLayers.length; i++) {
            const mockupLayer = mockupLayers[i];
            if (mockupLayer.visible === false || !mockupLayer.printarea_id) continue;

            const campaignArtwork = (this.campaign.campaign_artworks || []).find(item => item.printarea_id == mockupLayer.printarea_id);
            this.printAreas.push({
                id: mockupLayer.id,
                printarea_id: mockupLayer.printarea_id,
                artwork_id: campaignArtwork?.artwork_id || this.artwork?.id || null,
                top: mockupLayer.top || 0,
                left: mockupLayer.left || 0,
                width: mockupLayer.width,
                height: mockupLayer.height,
                rotate: mockupLayer.rotate || 0,
                opacity: mockupLayer.opacity ?? 1,
                masked_enable: mockupLayer.masked_enable || false,
                masked_image: mockupLayer.masked_image || null,
                masked_top: mockupLayer.masked_top || 0,
                masked_left: mockupLayer.masked_left || 0,
                masked_width: mockupLayer.masked_width || mockupLayer.width,
                masked_height: mockupLayer.masked_height || mockupLayer.height,
                artwork: {
                    width: this.artwork?.width,
                    height: this.artwork?.height,
                },
                layers: this.designLayers,
            });
        }
    }

    public isShowLayer(optionLayer)
    {
        if (!optionLayer) return false;
        if (!optionLayer.dependency) return true;

        const dependency = optionLayer.dependency;
        const dependencies = dependency.dependencies;
        const defaultCondition = dependency.show_by_default ? true : false;
        const conditions = [];

        if (typeof dependencies != 'undefined' && dependencies.length) {
            const dependencyItemConditions = [];

            for (let i = 0; i < dependencies.length; i++) {
                const dependencyItem = dependencies[i];
                const refLayer = this.layerById[dependencyItem.element];

                if (refLayer && !this.isShowLayer(refLayer)) {
                    dependencyItemConditions.push(false);
                } else if (refLayer && typeof refLayer.value != 'undefined' && refLayer.value !== null && refLayer.value !== '') {
                    if (Array.isArray(dependencyItem.value)) {
                        dependencyItemConditions.push(dependencyItem.value.includes(refLayer.value));
                    } else {
                        dependencyItemConditions.push(dependencyItem.value == refLayer.value);
                    }
                } else {
                    dependencyItemConditions.push(defaultCondition);
                }
            }

            if (dependencyItemConditions.length) {
                const reducer = dependency.match_type == 'any'
                    ? (accumulator, currentValue) => accumulator || currentValue
                    : (accumulator, currentValue) => accumulator && currentValue;

                conditions.push(dependencyItemConditions.reduce(reducer));
            }
        } else if (dependency.value && dependency.element) {
            const refLayer = this.layerById[dependency.element];
            let condition = false;

            if (typeof refLayer != 'undefined' && typeof refLayer.value != 'undefined' && refLayer.value !== null && refLayer.value !== '') {
                if (Array.isArray(dependency.value)) {
                    condition = dependency.value.includes(refLayer.value);
                } else {
                    condition = dependency.value == refLayer.value;
                }
            } else if (refLayer && this.isShowLayer(refLayer)) {
                condition = dependency.show_by_default ?? false;
            }

            conditions.push(condition);
        } else {
            conditions.push(true);
        }

        if (conditions.length) {
            const reducer = dependency.match_type == 'any'
                ? (accumulator, currentValue) => accumulator || currentValue
                : (accumulator, currentValue) => accumulator && currentValue;

            return conditions.reduce(reducer);
        }

        return defaultCondition;
    }

    public isShowGroupedClipart(option, layer)
    {
        if (!option) return false;

        for (let i = 0; i < (option.options || []).length; i++) {
            const optionItem = option.options[i];
            if (option.id == layer.value) return true;
            if (optionItem.url == layer.show_value) return true;
            if (getCdn(optionItem.url) == layer.show_value) return true;
        }

        return false;
    }

    public selectTemplate(templateId, rebuild = true)
    {
        for (let i = 0; i < this.artworks.length; i++) {
            const artwork = this.artworks[i];
            const template = (artwork.data || []).find(item => item.id == templateId);
            if (!template) continue;

            this.setActiveArtworkTemplate(artwork, template);
            if (rebuild) this.rebuild();
            return this.getSnapshot();
        }

        return this.getSnapshot();
    }

    public changeLayerOptionValue(optionItem, option, parentLayer = null)
    {
        return this.changeOptionValue(optionItem, option, parentLayer);
    }

    public changeOptionValue(optionItem, option, parentLayer = null)
    {
        if (!optionItem || !option) return this.getSnapshot();

        this.cloneTemplateLayers();

        const targetLayer = this.layerById[option.id] || option;
        const resolvedParentLayer = parentLayer ? (this.layerById[parentLayer.id] || parentLayer) : null;
        const linkedLayers = [targetLayer];
        const parentIds = [];

        if (resolvedParentLayer) {
            linkedLayers.push(resolvedParentLayer);
            parentIds.push(resolvedParentLayer.id);
        }

        for (let i = 0; i < this.templateLayers.length; i++) {
            const linkLayer = this.templateLayers[i];
            if (linkLayer.linked == targetLayer.id || (resolvedParentLayer && linkLayer.linked == resolvedParentLayer.id)) {
                linkedLayers.push(linkLayer);
            }
        }

        const showValue = optionItem.url ?? optionItem.show_value ?? optionItem.value ?? null;
        const optionName = optionItem.name ?? optionItem.value_name ?? null;

        if (targetLayer.clipart_reposition) {
            this.applyReposition(targetLayer, targetLayer.clipart_reposition);
        }

        if (targetLayer.grouped_reposition) {
            const repositionConfig = targetLayer.grouped_reposition.find(item => item.id == optionItem.id);
            if (repositionConfig) this.applyReposition(targetLayer, repositionConfig);
        }

        for (let i = 0; i < linkedLayers.length; i++) {
            const linkLayer = linkedLayers[i];
            if (!linkLayer) continue;

            linkLayer.optionItem = _.cloneDeep(optionItem);
            linkLayer.selected_name = optionName;

            if (parentIds.includes(linkLayer.id)) {
                // Parent layer (thường là form_type='grouped_clipart').
                // show_value = URL của item được chọn (để render).
                // value = id để định danh lựa chọn (cần thiết cho validation và payload).
                linkLayer.show_value = showValue;

                if (linkLayer.form_type == 'grouped_clipart') {
                    // Với grouped_clipart, value = id của group chứa item được chọn (option = group).
                    linkLayer.value = option?.id ?? showValue;
                } else if (typeof optionItem.id !== 'undefined' && optionItem.id !== null) {
                    linkLayer.value = optionItem.id;
                } else {
                    linkLayer.value = showValue;
                }

                linkLayer.validated = true;
                continue;
            }

            if (linkLayer.type == 'option') {
                linkLayer.value = optionItem.id;
                linkLayer.show_value = optionItem.id;
                linkLayer.validated = true;
            } else if (linkLayer.type == 'clipart') {
                linkLayer.show_value = showValue;
                linkLayer.value = linkLayer.show_value;

                if (linkLayer.form_type == 'grouped_clipart') {
                    linkLayer.value = optionItem.id;
                    linkLayer.show_value = optionItem.show_value;
                }

                linkLayer.validated = true;
            }
        }

        this.rebuild();
        return this.getSnapshot();
    }

    private applyReposition(layer, repositionConfig)
    {
        if (!layer || !repositionConfig) return;

        // Khởi tạo base nếu layer chưa được track (ví dụ: layer được set qua setTemplateLayers).
        if (typeof layer._baseTop === 'undefined') layer._baseTop = layer.top || 0;
        if (typeof layer._baseLeft === 'undefined') layer._baseLeft = layer.left || 0;

        layer.width = repositionConfig.width ?? layer.width;
        layer.height = repositionConfig.height ?? layer.height;
        layer.top = layer._baseTop + (repositionConfig.top || 0);
        layer.left = layer._baseLeft + (repositionConfig.left || 0);
    }

    public changeOptionGroupClipartValue(optionItem, option)
    {
        return this.changeOptionValue(optionItem, option);
    }

    public changeInputValue(layerOption, value)
    {
        this.cloneTemplateLayers();

        const targetLayer = this.layerById[layerOption.id] || layerOption;

        for (let i = 0; i < this.templateLayers.length; i++) {
            const layer = this.templateLayers[i];
            if (layer.id == targetLayer.id || layer.linked == targetLayer.id) {
                layer.value = value;
                layer.show_value = value;
                layer.validated = true;
            }
        }

        this.rebuild();
        return this.getSnapshot();
    }

    public changeUploadValue(layerOption, imageUrl, metadata = {})
    {
        this.cloneTemplateLayers();

        const targetLayer = this.layerById[layerOption.id] || layerOption;
        targetLayer.upload_image_url = imageUrl;
        targetLayer.upload_file = metadata.file || targetLayer.upload_file;

        const linkedLayers = [targetLayer];
        let parentLayer = null;
        if (targetLayer.parent_id) {
            parentLayer = this.templateLayers.find(layer => layer.grouped_clipart == targetLayer.parent_id);
        }

        for (let i = 0; i < this.templateLayers.length; i++) {
            const linkLayer = this.templateLayers[i];
            if (linkLayer.linked == targetLayer.id || (parentLayer && linkLayer.linked == parentLayer.id)) {
                linkedLayers.push(linkLayer);
            }
        }

        for (let i = 0; i < linkedLayers.length; i++) {
            linkedLayers[i].show_value = imageUrl;
            linkedLayers[i].value = imageUrl;
            linkedLayers[i].validated = true;
        }

        this.rebuild();
        return this.getSnapshot();
    }

    public changeLayerVisibility(layerOption, value)
    {
        this.cloneTemplateLayers();

        const targetLayer = this.layerById[layerOption.id] || layerOption;
        targetLayer.form_visibility_value = !!value;

        this.rebuild();
        return this.getSnapshot();
    }

    public getClipart(layer)
    {
        return this.clipartCategoryById[layer.clipart] || { options: [] };
    }

    public getClipartOptions(layer)
    {
        const clipart = this.getClipart(layer);
        return this.normalizeOptionItems(clipart.options || [], layer, 'url');
    }

    public getGroupedClipart(layer)
    {
        if (!layer.grouped_clipart) return [];

        const groups = this.groupedClipartsByParentId[layer.grouped_clipart] || [];
        return _.cloneDeep(groups).map(group => {
            group.thumbnail = group.thumbnail ? getCdn(group.thumbnail) : null;

            const normalizedOptions = this.normalizeOptionItems(group.options || [], layer, 'url');
            const selectedOption = normalizedOptions.find(option => {
                return option.url == layer.show_value || option.url == getCdn(layer.show_value);
            });

            group.show_value = selectedOption?.url || normalizedOptions[0]?.url || group.show_value || null;
            group.options = normalizedOptions.map(option => {
                option.active = option.url == layer.show_value || option.url == getCdn(layer.show_value);
                if (layer.value == group.id && !layer.show_value && option.url == group.show_value) {
                    option.active = true;
                }
                return option;
            });
            group.active = layer.value == group.id || !!selectedOption;
            group.isShow = this.isShowGroupedClipart(group, layer);
            return group;
        });
    }

    public getAdditionOptions(layer)
    {
        if (!layer.additional_option) return [];
        const category = this.clipartCategoryById[layer.additional_option];
        return this.normalizeOptionItems(category?.options || [], layer, 'id');
    }

    private normalizeOptionItems(options, layer, activeBy = 'id')
    {
        return _.cloneDeep(options).map(option => {
            if (option.thumbnail) option.thumbnail = getCdn(option.thumbnail);
            if (option.url) option.url = getCdn(option.url);
            if (option.show_value) option.show_value = getCdn(option.show_value);

            option.active = false;
            if (activeBy == 'url') {
                option.active = option.url == layer.show_value || option.url == getCdn(layer.show_value);
            } else {
                option.active = option.id == layer.value || option.id == layer.show_value;
            }

            return option;
        });
    }

    public getSnapshot()
    {
        return {
            campaign: this.campaign,
            campaignProduct: this.campaignProduct,
            campaignMockup: this.campaignMockup,
            mockup: this.getMockupPreview(),
            printAreas: this.printAreas,
            artwork: this.artwork,
            template: this.getTemplate(),
            templateOptions: this.templateOptions,
            layerOptions: this.layerOptions,
            designLayers: this.designLayers,
            fonts: this.getFonts(),
            config: this.getCustomizationConfig(),
            validation: this.validate(),
        };
    }

    public getMockupPreview()
    {
        const layers = (this.campaignMockup?.layers || []).filter(layer => layer.visible !== false).map(layer => {
            if (layer.url) {
                return {
                    id: layer.id,
                    type: 'image',
                    src: layer.url,
                    url: layer.url,
                    top: layer.top || 0,
                    left: layer.left || 0,
                    width: layer.width,
                    height: layer.height,
                    opacity: layer.opacity ?? 1,
                    position: layer.position ?? null,
                    rotate: layer.rotate || 0,
                };
            }

            if (layer.printarea_id) {
                return {
                    id: layer.id,
                    type: 'printarea',
                    printarea_id: layer.printarea_id,
                    top: layer.top || 0,
                    left: layer.left || 0,
                    width: layer.width,
                    height: layer.height,
                    opacity: layer.opacity ?? 1,
                    position: layer.position ?? null,
                    rotate: layer.rotate || 0,
                    masked_enable: layer.masked_enable || false,
                    masked_image: layer.masked_image || null,
                    layers: this.designLayers,
                };
            }

            return null;
        }).filter(Boolean);

        return {
            id: this.campaignMockup?.id,
            width: this.campaignMockup?.width,
            height: this.campaignMockup?.height,
            preview_url: this.campaignMockup?.preview_url ? getCdn(this.campaignMockup.preview_url) : null,
            preview_thumbnail: this.campaignMockup?.preview_thumbnail ? getCdn(this.campaignMockup.preview_thumbnail) : null,
            layers,
        };
    }

    public getCustomizationConfig()
    {
        const configs = {
            disable_make_change: true,
            layers: [],
            options: [],
            custom_type: {
                name: 'teeinblue'
            }
        };

        for (let i = 0; i < this.layerOptions.length; i++) {
            const optionLayer = this.layerOptions[i];
            if (!optionLayer.show_value) continue;
            if (!optionLayer.form_label) continue;

            const opt = {
                name: optionLayer.form_label,
                value: optionLayer.show_value,
            };

            if (optionLayer.optionItem) {
                opt.optionItem = _.cloneDeep(optionLayer.optionItem);
                delete opt.optionItem.options;
                if (optionLayer.optionItem.selected_name) opt.selected_name = optionLayer.optionItem.selected_name;
            }

            configs.options.push(opt);
        }

        for (let i = 0; i < this.templateLayers.length; i++) {
            const layer = _.cloneDeep(this.templateLayers[i]);
            let isShowLayer = this.isShowLayer(layer);
            if (typeof layer.form_visibility_value == 'boolean') {
                isShowLayer = layer.form_visibility_value && isShowLayer;
            }

            if (!layer.visible || !isShowLayer) continue;

            let layerConfig = {
                name: layer.name,
                type: layer.type,
                value: layer.value,
            };

            const transformConfigs = _.cloneDeep(layer);
            delete transformConfigs.value;
            delete transformConfigs.show_value;
            delete transformConfigs.url;
            delete transformConfigs.name;
            delete transformConfigs.custom_type;
            delete transformConfigs.optionItem;

            if (layer.type == 'text' && typeof layer.value != 'undefined') {
                layerConfig.value = layer.value;
            } else if (layer.type == 'option') {
                layerConfig.value = layer.value ?? layer.show_value;
            } else {
                if (layer.show_value) layerConfig.value = getCdn(layer.show_value);
                if (layer.url && !layer.show_value) layerConfig.value = getCdn(layer.url);
                if (!layerConfig.value) continue;
            }

            configs.layers.push({ ...layerConfig, ...transformConfigs });
        }

        return configs;
    }

    public validate()
    {
        const errors = [];

        for (let i = 0; i < this.artworks.length; i++) {
            const artwork = this.artworks[i];
            if (!artwork.template_settings || (artwork.data || []).length <= 1) continue;
            const hasValue = (artwork.data || []).some(template => template.active);
            if (!hasValue) {
                errors.push({
                    type: 'template',
                    artworkId: artwork.id,
                    message: artwork.template_settings?.label || 'Template is required',
                });
            }
        }

        for (let i = 0; i < this.layerOptions.length; i++) {
            const layer = this.layerOptions[i];
            const hasValue = !!(layer.value || layer.upload_image_url);
            if (!hasValue && layer.required == true && layer.visible && layer.form_type != 'static'
                && layer.form_type != 'linked' && layer.form_label
                && this.isShowLayer(layer)
                && (layer.form_visibility_value !== false || layer.form_type == 'text')) {
                errors.push({
                    type: 'layer',
                    layerId: layer.id,
                    label: layer.form_label,
                    message: `${layer.form_label} is required`,
                });
            }
        }

        return {
            isValid: errors.length === 0,
            errors,
        };
    }

    public getState()
    {
        const layers = {};
        for (let i = 0; i < this.templateLayers.length; i++) {
            const layer = this.templateLayers[i];
            layers[layer.id] = {
                value: layer.value,
                show_value: layer.show_value,
                form_visibility_value: layer.form_visibility_value,
                selected_name: layer.selected_name,
                optionItem: layer.optionItem,
            };
        }

        return {
            templateId: this.template?.id,
            layers,
        };
    }

    public getFonts()
    {
        return {
            google: this.googleFontFamilies,
            custom: this.customFontFamilies,
        };
    }

    public getMockupLayers()
    {
        return this.campaignMockup?.layers || [];
    }

    public getDesignLayers()
    {
        return this.designLayers;
    }

    public getArtwork()
    {
        return this.artwork;
    }

    public getTemplate()
    {
        if (!this.template) return null;
        return {
            ...this.template,
            layers: this.templateLayers,
        };
    }

    public getLayerOptions()
    {
        return this.layerOptions;
    }

    public getTemplateOptions()
    {
        return this.templateOptions;
    }

    public getPrintAreas()
    {
        return this.printAreas;
    }

    public getPreview()
    {
        return this.getMockupPreview();
    }

    public getData()
    {
        return this.getSnapshot();
    }

    public setTemplateOptions(options)
    {
        this.templateOptions = options;
    }

    public setTemplateLayers(layers)
    {
        this.templateLayers = layers || [];
        this.rebuild();
    }

    public getTemplateLayers()
    {
        return this.templateLayers;
    }
}

export default CustomizationTeeInBlue;
