system.directive('fulfillprintify', function() {
    return {
        controller: function($scope, $http, Upload) {
            this.__proto__ = new BaseFulfillController($scope, $http);
            $scope.axiosClient = axios.create();
            $scope.printifyConfigs = printifyConfigs;
            $scope.printifyAccount = null;
            $scope.accountIdChoosed = '';
            $scope.sizeguide = {};
            $scope.printifyOrderInfos = [];
            $scope.printifyProductInfos = [];

            $scope.printifyCurrentOrder = {};
            $scope.fullFillProvince = [];
            $scope.fullFillCities = [];

            $scope.printifyOrders = [];
            $scope.searchResult = [];
            $scope.pritifyState = {
                exporting: false,
                loading: true,
                typing: null,
                search_type: null,
                search: '',
                printAreas: []
            };
            $scope.fulFillLocale = null;
            $scope.productTemplateIds = [];
            $scope.needSaveTemplate = false;
            $scope.textNotify = '';

            $scope.initializePrintify = function() {

                // set account
                const accountId = localStorage.getItem('printify_shop_id');
                if (!accountId) { // set to default account
                    $scope.printifyAccount = printifyConfigs.accounts.find((acc) => {
                        return acc.default !== false;
                    });

                    if ($scope.printifyAccount) {
                        localStorage.setItem('printify_shop_id', $scope.printifyAccount.shop_id);
                    }

                } else {
                    $scope.printifyAccount = printifyConfigs.accounts.find((acc) => {
                        return parseInt(acc.shop_id) === parseInt(accountId);
                    });
                    if (typeof $scope.printifyAccount == 'undefined' || !$scope.printifyAccount) {
                        localStorage.clear('printify_shop_id');
                        return $scope.initializePrintify();
                    }
                }
                
                $scope.accountIdChoosed = angular.copy($scope.printifyAccount).shop_id.toString();

                $(document).mouseup(function(e) {

                    let container = $(".printify-data");
                    if (!container.is(e.target) && container.has(e.target).length === 0) {
                        if ($scope.pritifyState.searchingFor) {
                            $scope.pritifyState.searchingFor = null;
                        }
                    }

                    if (event.target === document.getElementById("errorModalPrintify")) {
                        document.getElementById("errorModalPrintify").style.display = "none";
                    }

                    if (event.target === document.getElementById("infoModalPrintify")) {
                        document.getElementById("infoModalPrintify").style.display = "none";
                    }

                    let containerChoose = $('.choose-input.dropdown-toggle')
                    if (!containerChoose.is(e.target) && containerChoose.has(e.target).length === 0) {
                        $scope.pritifyState.searchingColor = null;
                    }

                    safeApply();

                });

            }

            function fetchProfiles()
            {
                $scope.getDesignJobOrder($scope.printifyCurrentOrder);
                $scope.printifyCurrentOrder.items.forEach(element => {
                    element.designJob = checkAvailableDesign(element);
                });

                const requestObj = $scope.buildLocaleData('/print-suppliers/get-profile', {
                    order_items: $scope.printifyCurrentOrder.items
                }, $scope.fulFillLocale);

                $http.post(requestObj.url, requestObj.params).then(function(response) {
                    if (response.data.status === 'successful') {
                        $scope.profiles = {
                            profiles: response.data.profiles,
                            designs: response.data.designs
                        };
                        $scope.productTemplateIds = response.data.product_template_ids;
                        applyProfiles();
                    }
                }, function(error) {
                    toastr.error('Error load profiles!');
                });
            }

            let loadZipcode = function () {

                if (!$scope.printifyCurrentOrder.state_name && $scope.printifyCurrentOrder.country_id == 225) { // United Kingdom
                    $scope.printifyCurrentOrder.state_name = 'England';
                    $('#inputRegion').addClass('warning');
                    $('#warningBox').addClass('warning-box');
                }

                const requestObj = $scope.buildLocaleData('/print-suppliers/zipcode', {
                    country_id: $scope.printifyCurrentOrder.country_id,
                    code: $scope.printifyCurrentOrder.zip_code
                }, $scope.fulFillLocale);

                $http.get(requestObj.url, {params: requestObj.params}).then(function (response) {
                    if (response.data.status === 'successful') {
                        let _code = response.data.result;

                        if (!$scope.printifyCurrentOrder.state_name && _code.region) {
                            $scope.printifyCurrentOrder.state_name = _code.region;

                            if (!parseInt(_code.verified)) {
                                $('#inputRegion').addClass('warning');
                                $('#warningBox').addClass('warning-box');
                            }

                        }
                        if (!$scope.printifyCurrentOrder.city_name && _code.city) {
                            $scope.printifyCurrentOrder.city_name = _code.city;

                            if (!parseInt(_code.verified)) {
                                $('#inputCity').addClass('warning');
                                $('#warningBox').addClass('warning-box');
                            }
                        }
                    }
                }, function (error) {
                    toastr.error('Error load zipcode!');
                });
            }

            function applyProfiles()
            {
                $scope.printifyCurrentOrder.items.forEach(async printOrderItem => {

                    let profile = null;
                    let designs;

                    if (typeof printOrderItem.printify_state == 'undefined' || !printOrderItem.printify_state) {
                        printOrderItem.printify_state = {};
                    }

                    if (isTemplateProduct(printOrderItem.product_id)) {
                        profile = $scope.profiles.profiles.find(function (item) {
                            return parseInt(item.product_id) === parseInt(printOrderItem.product_id)
                                && item.is_template_product;
                        });
                        designs = $scope.findDesign(printOrderItem, true, $scope.profiles.designs);
                    } else {
                        profile = $scope.profiles.profiles.find(function (item) {
                            return parseInt(item.product_sku_id) === parseInt(printOrderItem.product_sku_id)
                                && !item.is_template_product;
                        });
                        designs =  $scope.findDesign(printOrderItem, false, $scope.profiles.designs);
                    }

                    printOrderItem.printify_state.patternDesigns = [];
                    if(designs && designs.length) {
                        printOrderItem.printify_state.patternDesigns = designs;

                        setTimeout(() => {
                            $('[data-magnify=gallery]').magnify({
                                zIndex: 10000
                            });
                        }, 500);
                    }

                    if(profile) {
                        applySingleProfile(profile, printOrderItem);
                    }

                });
            }

            function isTemplateProduct(productId) {
                return $scope.productTemplateIds.includes(productId);
            }

            $scope.changeAccount = function() {
                $scope.printifyAccount = printifyConfigs.accounts.find((acc) => {
                    return parseInt(acc.shop_id) === parseInt($scope.accountIdChoosed);
                })
                localStorage.setItem('printify_shop_id', $scope.printifyAccount.shop_id);
            }

            $scope.openSearchColors = function (item) {
                $scope.pritifyState.searchingColor = item.id;
                $('#btnSearchColor-' + item.id).dropdown();
                setTimeout(() => {
                    $('#inputSearchColor-' + item.id).focus();
                }, 100);
            }

            $scope.searchColors = function (item) {
                if ($scope.pritifyState.typing) {
                    clearTimeout($scope.pritifyState.typing);
                }
                $scope.pritifyState.typing = setTimeout(() => {
                    let search = item.printify_state.colorSearch;
                    let colors = angular.copy(item.printify_state.colors);

                    let colorsSortable = [];
                    if(search) {
                        colors.forEach(color => {
                            if(color.label.toLowerCase().search(search.toLowerCase()) >= 0) {
                                colorsSortable.push(color);
                            }
                        });
                    } else {
                        colorsSortable = colors;
                    }

                    item.printify_state.sortedColors = colorsSortable.sort(function (a, b) {
                        if (a.label < b.label) {
                            return -1;
                        }
                        if (a.label > b.label) {
                            return 1;
                        }
                        return 0;
                    });

                    safeApply();

                }, 200);
            }

            $scope.searchProviders = function (item) {
                if ($scope.pritifyState.typing) {
                    clearTimeout($scope.pritifyState.typing);
                }
                $scope.pritifyState.typing = setTimeout(() => {
                    let search = item.printify_state.providerSearch;
                    let providers = angular.copy(item.printify_state.avaiableProviders);

                    let providersFiltered = [];
                    if(search) {
                        providers.forEach(provider => {
                            if(provider.name.toLowerCase().search(search.toLowerCase()) >= 0) {
                                providersFiltered.push(provider);
                            }
                        });
                    } else {
                        providersFiltered = providers;
                    }

                    item.printify_state.providersFiltered = providersFiltered;

                    safeApply();

                }, 200);
            }

            $scope.openFulfillForm = async function(orderOrCard) 
            {
                let order = angular.copy(orderOrCard);

                if (typeof orderOrCard.order_id != 'undefined') 
                {
                    $scope.loadingOrderInfo = true; 
                    order = await $scope.loadOrderInfo(orderOrCard.order_id, orderOrCard.locale_code);
                    $scope.loadingOrderInfo = false;

                    $scope.fulFillLocale = orderOrCard.locale_code;

                    safeApply();

                    if (!order) return toastr.error('Error! Cannot find order infomation...');

                } else {
                    if (typeof order.location != 'undefined' && order.location !== '') {
                        $scope.fulFillLocale = angular.copy(order.location);
                    } else {
                        $scope.fulFillLocale = null;
                    }
                }

                $scope.needSaveTemplate = false;
                $scope.printifyCurrentOrder = angular.copy(order);
                $scope.getSuggestsPrinting($scope.printifyCurrentOrder.code);

                if (!$scope.printifyCurrentOrder.customer) $scope.printifyCurrentOrder.customer = {};

                if ($scope.printifyCurrentOrder.attributes.customer_info) {
                    $scope.printifyCurrentOrder.customer.phone = $scope.printifyCurrentOrder.attributes.customer_info.phone;
                    $scope.printifyCurrentOrder.customer.full_name = $scope.printifyCurrentOrder.attributes.customer_info.full_name;
                }

                if ($scope.printifyCurrentOrder.shipping_type === 'express')
                    $scope.printifyCurrentOrder.shipping_type = 'express';
                else if ($scope.printifyCurrentOrder.shipping_type === 'express-priority')
                    $scope.printifyCurrentOrder.shipping_type = 'express-priority';
                else
                    $scope.printifyCurrentOrder.shipping_type = 'standard';

                if ($scope.printifyCurrentOrder.customer) {

                    if (typeof $scope.printifyCurrentOrder.attributes.gift_info != 'undefined' && $scope.printifyCurrentOrder.attributes.gift_info.name) {
                        $scope.printifyCurrentOrder.customer.full_name = $scope.printifyCurrentOrder.attributes.gift_info.name;
                        if ($scope.printifyCurrentOrder.attributes.gift_info.phone) {
                            $scope.printifyCurrentOrder.customer.phone = $scope.printifyCurrentOrder.attributes.gift_info.phone;
                        }
                    }

                    $scope.printifyCurrentOrder.customer.full_name = $scope.capitalizeFirstLetter($scope.printifyCurrentOrder.customer.full_name);
                    if(user_email) {
                        $scope.printifyCurrentOrder.customer.email = user_email;
                    }
                }
                
                for (let i = 0; i < $scope.printifyCurrentOrder.items.length; i++) {
                    $scope.getCustomConfigs($scope.printifyCurrentOrder.items[i]);
                }

                if(!order.state_name)
                    await $scope.getFulfillProvince();

                if(!order.city_name)
                    await $scope.getFulfillCity();

                fetchProfiles();
                loadZipcode();

                $('#modalFulfillPrintify').modal({
                    modal: true,
                    persist: true,
                    position: [30, 0],
                    autoPosition: true
                });
            }

            $scope.getFulfillProvince = function() {
                if ($scope.printifyCurrentOrder.customer && $scope.printifyCurrentOrder.customer.province_id) {
                    return new Promise(function(resolve) {
                        $http.get(base_api_url + '/province', { 
                            params:{ 
                                page_size: -1, filters: 'country_id=' + $scope.printifyCurrentOrder.id 
                            }
                        }).then(function(response) {
                            $scope.fullFillProvince = response.data.result;
                            findFulfillProvince($scope.fullFillProvince, $scope.printifyCurrentOrder.customer.province_id);
                            resolve();
                        }, function(error) {
                            console.log(error);
                            resolve();
                        });
                    });
                }
            }

            $scope.getProfileBlueprint = function(blueprintId) {
                return new Promise(function(resolve) {
                    const requestObj = $scope.buildLocaleData(printifyConfigs.apiPrefix + 'fetch-blueprint', {blueprint_id: blueprintId}, $scope.fulFillLocale);
                    $http.get(requestObj.url, { params: requestObj.params }).then(function(response) {
                        if (response.data.status === "successful") {
                            resolve(response.data);
                        }
                    }, function(error) {
                        console.log(error);
                        resolve();
                    });
                });
            }

            function findFulfillProvince(provinces, id) {
                if (id && provinces.length) {
                    $scope.printifyCurrentOrder.province = provinces.find((province) => {
                        return province.id = id;
                    });
                }
            }

            $scope.getFulfillCity = function() {
                if ($scope.printifyCurrentOrder.customer.district_id && $scope.printifyCurrentOrder.province) {
                    return new Promise(function(resolve) {
                        $http.get(base_api_url, { 
                            params: { 
                                embeds: 'communes', page_size: -1, filters: 'province_id=' + $scope.printifyCurrentOrder.province.id 
                            } 
                        }).then(function(response) {
                            $scope.fullFillCities = response.data.result;
                            findFulfillCity($scope.fullFillCities, $scope.printifyCurrentOrder.customer.district_id);
                            resolve();
                        }, function(error) {
                            console.log(error);
                            resolve();
                        });
                    });
                }

            }

            function findFulfillCity(cities, id) {
                if (id && cities.length) {
                    $scope.printifyCurrentOrder.city = cities.find((city) => {
                        return city.id = id;
                    });
                }
            }

            $scope.exportPrintifyOrder = function() {
                const requestObj = $scope.buildLocaleData(printifyConfigs.apiPrefix + 'export-printify', {}, $scope.fulFillLocale);
                $http.get(requestObj, {params: requestObj.params}).then(function(response) {
                    if (response.data.status === 'successful') {
                        $scope.printifyOrders = response.data.result;
                        $scope.pritifyState.loading = false;
                        $scope.printifyProfiles = response.data.profiles;
                        $scope.updateProfile();

                        safeApply();
                    }

                    setTimeout(() => {
                        $('.loader.size').hide();
                    }, 1000);

                }, function(error) {
                    toastr.error('Error load printify order!');
                });
            }

            $scope.openSearchBlueprint = function(printOrderItem) {
                $scope.searchResult = [];

                $scope.pritifyState.searchingFor = printOrderItem.id;
                $scope.pritifyState.search_type = 'blueprint';
                $scope.pritifyState.search = '';

                $scope.fetchBlueprint();
                setTimeout(() => {
                    $('#searchInput-' + printOrderItem.id).focus();
                });
            }

            $scope.openSearchPrintProvider = function(printOrderItem) {
                $scope.searchResult = [];

                $scope.pritifyState.searchingFor = printOrderItem.id;
                $scope.pritifyState.search_type = 'print_provider';
                $scope.pritifyState.search = '';

                $scope.pritifyState.currentPrintOrderItem = printOrderItem;

                $scope.fetchPrintProvider();
                setTimeout(() => {
                    $('#searchInput-' + printOrderItem.id).focus();
                });
            }

            $scope.openSearchVariant = function(printOrderItem) {
                $scope.searchResult = [];

                $scope.pritifyState.searchingFor = printOrderItem.id;
                $scope.pritifyState.search_type = 'variant';
                $scope.pritifyState.search = '';

                $scope.fetchVariant();
                setTimeout(() => {
                    $('#searchInput-' + printOrderItem.id).focus();
                });
            }

            $scope.routeFetch = function() {
                if ($scope.pritifyState.search_type === "blueprint") {
                    $scope.fetchBlueprint();
                } else if ($scope.pritifyState.search_type === "print_provider") {
                    $scope.fetchPrintProvider();
                } else if ($scope.pritifyState.search_type === "variant") {
                    $scope.fetchVariant();
                }
            }

            $scope.fetchVariant = function() {
                if ($scope.pritifyState.typing) {
                    clearTimeout($scope.pritifyState.typing);
                }

                try {
                    $scope.pritifyState.searching = true;
                    let currentOrderSate = $scope.pritifyState.currentPrintOrderItem.printify_state;
                    let search = $scope.pritifyState.search;

                    $scope.pritifyState.typing = setTimeout(() => {
                        const requestObj = $scope.buildLocaleData(printifyConfigs.apiPrefix + 'fetch-variant', {
                            blueprint_id: currentOrderSate.blueprint.blueprint_id,
                            print_provider_id: currentOrderSate.print_provider.print_provider_id,
                            search: search
                        }, $scope.fulFillLocale);

                        $http.get(requestObj.url, { params: requestObj.params }).then(function(response) {
                                if (response.data.status === 'successful') {
                                    $scope.searchResult = response.data.result;
                                }
                                $scope.pritifyState.searching = false;
                            }, function(error) {
                                toastr.error('Error load printify varian!');
                                $scope.pritifyState.searching = false;
                            });
                    }, 450);
                } catch (error) {
                    toastr.error(JSON.stringify(error));
                    console.log(error);
                }

            }

            $scope.fetchPrintProvider = function() {
                if ($scope.pritifyState.typing) {
                    clearTimeout($scope.pritifyState.typing);
                }

                try {
                    $scope.pritifyState.searching = true;
                    let currentOrderSate = $scope.pritifyState.currentPrintOrderItem.printify_state;
                    let search = $scope.pritifyState.search;

                    $scope.pritifyState.typing = setTimeout(() => {
                        const requestObj = $scope.buildLocaleData(printifyConfigs.apiPrefix + 'fetch-print-provider', {
                            blueprint_id: currentOrderSate.blueprint.blueprint_id,
                            search: search
                        }, $scope.fulFillLocale);

                        $http.get(requestObj.url, { params: requestObj.params }).then(function(response) {
                            if (response.data.status === 'successful') {
                                $scope.searchResult = response.data.result;
                            }
                            $scope.pritifyState.searching = false;
                        }, function(error) {
                            toastr.error('Error load printify print provider!');
                            $scope.pritifyState.searching = false;
                        });
                    }, 450);

                } catch (error) {
                    toastr.error(JSON.stringify(error));
                    console.log(error);
                }

            }

            $scope.fetchBlueprint = function() {
                if ($scope.pritifyState.typing) {
                    clearTimeout($scope.pritifyState.typing);
                }
                $scope.pritifyState.typing = setTimeout(() => {
                    $scope.pritifyState.searching = true;
                    const requestObj = $scope.buildLocaleData(printifyConfigs.apiPrefix + 'fetch-blueprint', {search: $scope.pritifyState.search}, $scope.fulFillLocale);

                    $http.get(requestObj.url, { params: requestObj.params }).then(function(response) {
                            if (response.data.status === 'successful') {
                                $scope.searchResult = response.data.result;
                                $scope.pritifyState.search_type = 'blueprint';
                                $scope.pritifyState.searching = false;
                            }
                        }, function(error) {
                            toastr.error('Error load printify blueprint!');
                            $scope.pritifyState.searching = false;
                        });
                }, 450);

            }

            $scope.chooseResult = function(result, printOrderItem) 
            {
                $scope.pritifyState.searchingFor = null;
                if ($scope.pritifyState.search_type === 'blueprint') 
                {
                    if (typeof printOrderItem.printify_state == 'undefined' || !printOrderItem.printify_state) {
                        printOrderItem.printify_state = {};
                    }

                    printOrderItem.printify_state.blueprint = result;

                    printOrderItem.printify_state.sizes = null;
                    printOrderItem.printify_state.colors = null;

                    printOrderItem.printify_state.color_id = null;
                    printOrderItem.printify_state.size_id = null;
                    printOrderItem.printify_state.printAreas = [];
                    printOrderItem.printify_state.options = {};

                    printOrderItem.printify_state.loading = true;
                    $scope.loadBlueprintPrintify(printOrderItem.printify_state.blueprint, printOrderItem);
                }

                safeApply();
            }

            $scope.choosePrintprovider = function (printOrderItem, variant, provider) {
                if(variant.status !== 'out-of-stock') {
                    
                    printOrderItem.printify_state.loading = true;
                    const blueprintId = printOrderItem.printify_state.blueprint.blueprint_id;

                    getBlueprintVariants(blueprintId, provider.id).then(response => {

                        printOrderItem.printify_state.variants = response.data.variants

                        for (let i = 0; i < printOrderItem.printify_state.providersFiltered.length; i++) {
                            printOrderItem.printify_state.providersFiltered[i].selected = false;
                            if(printOrderItem.printify_state.providersFiltered[i].id == provider.id)
                                printOrderItem.printify_state.providersFiltered[i].selected = true;
                        }
    
                        for (let i = 0; i < printOrderItem.printify_state.avaiableProviders.length; i++) {
                            printOrderItem.printify_state.avaiableProviders[i].selected = false;
                            if(printOrderItem.printify_state.avaiableProviders[i].id == provider.id)
                                printOrderItem.printify_state.avaiableProviders[i].selected = true;
                        }
    
                        printOrderItem.printify_state.printProvider = provider;
                        printOrderItem.printify_state.variant = variant;
                        
                        loadDesign(printOrderItem, variant);

                        printOrderItem.printify_state.loading = false;
                        safeApply();

                    });
                }
            }

            function loadDesign(printOrderItem, variant) {
                
                let printableAreas = [];

                const fullVariantData = printOrderItem.printify_state.variants.find((fVariant) => {
                    return fVariant.id = variant.id;
                });

                if (fullVariantData) {
                    printableAreas = fullVariantData.placeholders.map((placeholder) => {
                        return placeholder.position;
                    });
                }

                if (!printableAreas.length) {
                    const printPositionLength = printOrderItem.printify_state.printProvider.printPosition.length;
                    for (let i = 0; i < printPositionLength; i++) {
                        const printPosition = printOrderItem.printify_state.printProvider.printPosition[i];
                        printableAreas.push(printPosition.position);
                    }
                }

                printOrderItem.printify_state.printAreas = [];
                printOrderItem.printify_state.currentDesignUrl = '';

                if(typeof printOrderItem.printify_state.designs == 'undefined' || !printOrderItem.printify_state.designs) {
                    printOrderItem.printify_state.designs = [];
                }
                
                let hasFrontSide = false;
                let hasBackSide = false;
    
                for (let index = 0; index < printableAreas.length; index++) {
                    let printArea = printableAreas[index];
                    let areaDisplay = capitalizeFirstLetter(printArea.trim());

                    if (areaDisplay === 'Front') { hasFrontSide = true; continue; }
                    if (areaDisplay === 'Back') { hasBackSide = true; continue; }

                    printOrderItem.printify_state.printAreas.push(areaDisplay);
                }

                if(hasBackSide) printOrderItem.printify_state.printAreas.push('Back side');
                if(hasFrontSide) printOrderItem.printify_state.printAreas.push('Front side');

                printOrderItem.printify_state.printAreas = printOrderItem.printify_state.printAreas.reverse();

                if( // Nếu không có hoặc rỗng thì apply design từ mẫu vào
                    hasFrontSide && 
                    (typeof printOrderItem.printify_state.designs['Front side'] == 'undefined' || !printOrderItem.printify_state.designs['Front side']) &&
                    typeof printOrderItem.printify_state.patternDesigns != 'undefined' && 
                    printOrderItem.printify_state.patternDesigns.length
                ) {
                    printOrderItem.printify_state.designs['Front side'] = printOrderItem.printify_state.patternDesigns[0].url;
                    $scope.changeDesignUrl('Front side', printOrderItem);
                }

                if (printOrderItem.printify_state.printAreas.length) {
                    printOrderItem.printify_state.selectArea = printOrderItem.printify_state.printAreas[0];
                }
            }

            $scope.loadBlueprintPrintify = function (blueprint, printOrderItem) 
            {
                printOrderItem.printify_state.avaiableProviders = [];
                printOrderItem.printify_state.printProvider = null;
                printOrderItem.printify_state.variant = null;

                if (typeof printOrderItem.printify_state.options == 'undefined') {
                    printOrderItem.printify_state.options = {};
                }

                let params = new URLSearchParams({
                    end_point: 'blueprints/' + blueprint.blueprint_id,
                    base_api: 'https://printify.com/product-catalog-service/api/v1/', // https://printify.com/api/v1/blueprints/formatted/
                    shop_id: $scope.printifyAccount.shop_id
                }).toString();

                const requestObj = $scope.buildLocaleData('/print-suppliers/printify/api?' + params, {}, $scope.fulFillLocale);

                $scope.axiosClient.get(requestObj.url).then(response => {
                    let blueprintDetail = response.data;
                   
                    printOrderItem.printify_state.providerOptions = getProviderOptions(blueprintDetail.printProviders);

                    /* for (let index = 0; index < blueprintDetail.printProviders.length; index++) 
                    {
                        let printProvider = blueprintDetail.printProviders[index];
                        let optionItems = [];

                        for (let j = 0; j < printProvider.options.length; j++) {
                            const option = printProvider.options[j];
                            optionItems = [... optionItems, ... option.items];
                        }

                        for (let j = 0; j < printProvider.variants.length; j++) 
                        {
                            let printProviderVariant = printProvider.variants[j];

                            const variantLabels = printProviderVariant.options.map((option) => 
                            {
                                const optionItem = optionItems.find((item) => {
                                    return item.id == option;
                                })

                                option = optionItem.label;

                                return option;
                            });

                            printProviderVariant.label = variantLabels.join(' ');
                        }

                        for (let j = 0; j < printProvider.options.length; j++) {
                            let option = printProvider.options[j];
                            if(typeof option != 'undefined' && option) {

                                if(option.type === 'size') {
                                    getBlueprintOptionItems(option.items, sizes);
                                }
                                if(option.type === 'color' || option.type === 'des') {
                                    getBlueprintOptionItems(option.items, colors);
                                }
                            
                            }
                            
                        }
                    } */

                    /* if (typeof blueprintDetail.sizeGuide != 'undefined' && blueprintDetail.sizeGuide) {
                        printOrderItem.printify_state.sizeGuide = buideSizeGuide(blueprintDetail.sizeGuide);
                        if($scope.sizeguide) {
                            for (const key in sizes) {
                                if (Object.hasOwnProperty.call(sizes, key)) {
                                    if($scope.sizeguide[sizes[key].label]) {
                                        sizes[key].sizeguide = $scope.sizeguide[sizes[key].label];
                                    }
                                }
                            }
                        }
                    } */

                    let sortedColors = [];
                    if (typeof printOrderItem.printify_state.providerOptions.color != 'undefined')
                    {
                        sortedColors = printOrderItem.printify_state.providerOptions.color.sort(function(a, b) {
                            if(a.label < b.label) { return -1; }
                            if(a.label > b.label) { return 1; }
                            return 0;
                        });
                    }

                    let sizes = [];
                    if (typeof printOrderItem.printify_state.providerOptions.size != 'undefined')
                    {
                        sizes = printOrderItem.printify_state.providerOptions.size;
                    }
                    
                    printOrderItem.printify_state.decorators = blueprintDetail.printProviders;
                    printOrderItem.printify_state.sizes = sizes;
                    printOrderItem.printify_state.colors = sortedColors;
                    printOrderItem.printify_state.sortedColors = sortedColors;

                    printOrderItem.printify_state.loading = false;

                    if(printOrderItem.printify_state.color_id) {
                        let colorOption = printOrderItem.printify_state.colors.find((color) => {
                            return printOrderItem.printify_state.color_id == color.id;
                        });
                        if(colorOption) printOrderItem.printify_state.selectedColor = colorOption;
                    }

                    $scope.changeVariantOption(printOrderItem);

                    $scope.$apply();

                    $('.cost-tooltip').tooltip();
                });
            }
            
            const getProviderOptions = (printProviders) =>
            {
                const providerOptions = {};

                for (let i = 0; i < printProviders.length; i++) 
                {
                    const options = printProviders[i].options;

                    for (let j = 0; j < options.length; j++) {
                        const option = options[j];
                        if (typeof providerOptions[option.type] == 'undefined') {
                            providerOptions[option.type] = [];
                        }
                        providerOptions[option.type] = [... providerOptions[option.type], ... option.items];
                    }
                }

                for (const key in providerOptions) {
                    if (Object.hasOwnProperty.call(providerOptions, key)) {
                        providerOptions[key] = getUniqueById(providerOptions[key]);
                    }
                }

                return providerOptions;
            }

            const getUniqueById = (arr) => {
                const unique = new Map(arr.map(item => [item.id, item]));
                return Array.from(unique.values());
            }

            const arraysMatch = (arr1, arr2) => 
            {
                if (arr1.length !== arr2.length) {
                    return false;
                }
            
                const sortedArr1 = arr1.slice().sort();
                const sortedArr2 = arr2.slice().sort();
            
                for (let i = 0; i < sortedArr1.length; i++) {
                    if (sortedArr1[i] != sortedArr2[i]) {
                        return false;
                    }
                }
            
                return true;
            }

            function buideSizeGuide(sizeGuide) {
                let sizes = sizeGuide.sizes;
                let sizebuild = {};
                sizeGuide.types.forEach(element => {
                    let ranges = element.ranges;
                    for (let i = 0; i < ranges.length; i++) {
                        let value = ranges[i].from;
                        let size = sizes[i];
                        
                        if(!sizebuild[size]) sizebuild[size] = [];
                        sizebuild[size].push(element.name + ' ' + value);

                    }
                });

                $scope.sizeguide = sizebuild;
                return sizebuild;
            }

            $scope.changeVariantOption = function(printOrderItem) 
            {
                let avaiableProviders = {};
                printOrderItem.printify_state.printProvider = null;

                let hasColors = true;
                if(!printOrderItem.printify_state.colors.length) {
                    hasColors = false;
                }

                const decorators = printOrderItem.printify_state.decorators;
                const variantOptions = printOrderItem.printify_state.options;

                for (let i = 0; i < decorators.length; i++)
                {
                    const variants = decorators[i].variants;
                    for (let j = 0; j < variants.length; j++) {
                        const variant = variants[j];
                        if (arraysMatch(variant.options, Object.values(variantOptions))) {

                            if(!avaiableProviders[decorators[i].id]) {
                                avaiableProviders[decorators[i].id] = {
                                    id: decorators[i].id,
                                    shipping: decorators[i].shipping,
                                    fulfillmentStats: decorators[i].fulfillmentStats,
                                    name: decorators[i].name,
                                    printPosition: decorators[i].printPosition,
                                    sort: 0,
                                    variants: {},
                                    variant: variant
                                };
                            }

                            if(!avaiableProviders[decorators[i].id].variants[variant.id]) {
                                avaiableProviders[decorators[i].id].variants[variant.id] = variant;
                                if(variant.available) avaiableProviders[decorators[i].id].sort = 1;
                            }

                        }
                    }
                }

                /* if(printOrderItem.printify_state.size_id && (!hasColors || printOrderItem.printify_state.color_id)) {
                    
                    let selectedVariant = null;
                    let selectedProvider = null;
                    let decorators = printOrderItem.printify_state.decorators;

                    for (let index = 0; index < decorators.length; index++)
                    {
                        const variants = decorators[index].variants;

                        for (let j = 0; j < variants.length; j++) {

                            const variant = variants[j];

                            if(
                                variant.options.indexOf(parseInt(printOrderItem.printify_state.size_id)) >= 0 && 
                                (!hasColors || variant.options.indexOf(parseInt(printOrderItem.printify_state.color_id)) >= 0)
                            ) {

                                if(!avaiableProviders[decorators[index].id]) {
                                    avaiableProviders[decorators[index].id] = {
                                        id: decorators[index].id,
                                        shipping: decorators[index].shipping,
                                        fulfillmentStats: decorators[index].fulfillmentStats,
                                        name: decorators[index].name,
                                        printPosition: decorators[index].printPosition,
                                        sort: 0,
                                        variants: {},
                                        variant: variant
                                    };
                                }
                                
                                if(!avaiableProviders[decorators[index].id].variants[variant.id]) {
                                    avaiableProviders[decorators[index].id].variants[variant.id] = variant;
                                    if(variant.available) avaiableProviders[decorators[index].id].sort = 1;
                                }

                                if (avaiableProviders[decorators[index].id].id == 99) { // "Printify Choice"
                                    avaiableProviders[decorators[index].id].sort = 999;
                                } else {
                                    avaiableProviders[decorators[index].id].sort = -variant.costs[0].result;
                                }
                                
                                // load form profile
                                if(printOrderItem.printify_state.variant_id && printOrderItem.printify_state.print_provider_id) {
                                    if(printOrderItem.printify_state.variant_id == variant.id && printOrderItem.printify_state.print_provider_id === decorators[index].id) {
                                        printOrderItem.printify_state.loading = true;
                                        getBlueprintVariants(printOrderItem.printify_state.blueprint.blueprint_id, printOrderItem.printify_state.print_provider_id).then(response => {

                                            printOrderItem.printify_state.variants = response.data.variants

                                            avaiableProviders[decorators[index].id].selected = true;
                                            selectedVariant = variant;
                                            selectedProvider = avaiableProviders[decorators[index].id];

                                            printOrderItem.printify_state.loading = false;
                                            safeApply();
                                        });
                                    }
                                }

                            }
                        }
                    }

                    // apply from profile
                    if(selectedProvider && selectedVariant) 
                    {
                        printOrderItem.printify_state.printProvider = selectedProvider;
                        printOrderItem.printify_state.variant = selectedVariant;

                        loadDesign(printOrderItem, selectedVariant);
                    }
                } */

                let availableProvidersSortable = [];
                for (let id in avaiableProviders) {
                    availableProvidersSortable.push(avaiableProviders[id]);
                }

                availableProvidersSortable.sort(function(a, b) {
                    return b.sort - a.sort;
                });

                printOrderItem.printify_state.avaiableProviders = availableProvidersSortable;
                printOrderItem.printify_state.providersFiltered = availableProvidersSortable;

                $('.cost-tooltip').tooltip();
            }

            function getBlueprintVariants(blueprintId, providerId)
            {
                const params = new URLSearchParams({
                    end_point: blueprintId + '/print_providers/' + providerId + '/variants.json',
                    base_api: 'https://api.printify.com/v1/catalog/blueprints/',
                    shop_id: $scope.printifyAccount.shop_id
                }).toString();

                const requestObj = $scope.buildLocaleData('/print-suppliers/printify/api?' + params, {}, $scope.fulFillLocale);
                return $scope.axiosClient.get(requestObj.url);
            }

            function getBlueprintOptionItems(items, targetOptions) {
                for (let i = 0; i < items.length; i++) {

                    if(typeof targetOptions[items[i].id] == 'undefined') {
                        targetOptions[items[i].id] = {};
                    } else if (targetOptions[items[i].id]) {
                        continue;
                    }

                    targetOptions[items[i].id] = {
                        id: items[i].id,
                        label: items[i].label
                    };

                    if(items[i].colors) {
                        targetOptions[items[i].id].colors = items[i].colors;
                    }
                }
            }

            function capitalizeFirstLetter(string) {
                let _res = '';
                if(string && typeof string == 'string')
                    _res = string.charAt(0).toUpperCase() + string.slice(1);
                return _res;
            }

            $scope.capitalizeFirstLetter = capitalizeFirstLetter;

            $scope.getSummaryShipping = function (data) {
                let max = 0; let min = 999999;
                for (let i = 0; i < data.length; i++) {
                    if(data[i].first < min)
                        min = parseFloat(data[i].first);
                    if(data[i].first > max)
                        max = parseFloat(data[i].first);
                }

                if(min !== max) 
                    return 'From ' + (min/100) + ' to ' + (max/100) + ' USD';
                else 
                    return 'From ' + (min/100) + ' USD';
            }

            $scope.changeDesignUrl = function (option, item) {
                // reset dữ liệu position
                resetPosition(option, item);

                if(item.printify_state.designs[option] && isValidHttpUrl(item.printify_state.designs[option]))
                    $('#designImage-' + item.id + '-' + $scope.replaceSpace(option)).attr('src', item.printify_state.designs[option]);
                else 
                    $('#designImage-' + item.id + '-' + $scope.replaceSpace(option)).attr('src', 'https://dummyimage.com/400x200/f8f8f8/4a4a4a.png&text=Click+to+upload+design');
            }

            function resetPosition(option, item) {
                if(typeof item.printify_state.designPositions != "undefined") {
                    try {
                        let keyOption = option.toLowerCase().split(' ')[0];
                        let arrPosition = ['frames', 'position', 'positionPrinterval'];
                        for (let i = 0; i < arrPosition.length; i++) {
                            if(typeof item.printify_state.designPositions[arrPosition[i]] == 'undefined')
                                return;
                        }
                        delete item.printify_state.designPositions.frames[keyOption];
                        delete item.printify_state.designPositions.position[keyOption];
                        delete item.printify_state.designPositions.positionPrinterval[keyOption];
                    } catch (error) {
                        console.warn(error);
                    }
                }
            }

            $scope.replaceSpace = function (param) {
                return param.replace(/\s/g, "");
            }

            function isValidHttpUrl(string) {
                let url;
                try {
                    url = new URL(string);
                } catch (_) {
                    return false;  
                }
                return url.protocol === "http:" || url.protocol === "https:";
            }

            $scope.orderPrintify = async function()
            {
                safeApply();

                let printervalOrder = $scope.printifyCurrentOrder;
                
                let fullName = printervalOrder.customer.full_name;
                let partsName = fullName.split(' ');
                let lengthName = partsName.length;

                let lastName = partsName.pop();
                let firstName = partsName.join(' ');

                if (lengthName < 2) {
                    firstName = lastName;
                }

                let region = ' ';
                if(printervalOrder.state_name){
                    region = printervalOrder.state_name;
                }/*  if(typeof printervalOrder.province != 'undefined' && printervalOrder.province.name) {
                    // region = printervalOrder.province.name;
                } */

                let city = ' ';
                if(printervalOrder.city_name){
                    city = printervalOrder.city_name;
                }/*  else if(typeof printervalOrder.city != 'undefined' && printervalOrder.city.name) {
                    // city = printervalOrder.city.name;
                } */

                let shippingType = printervalOrder.shipping_type === 'standard' ? 1 : 2;
                if (printervalOrder.shipping_type == 'express-priority') {
                    shippingType = 3;
                }

                let printifyOrder = {
                    "external_id": "printerval-" + printervalOrder.code + '-' + new Date().getTime(),
                    "label": "API" + printervalOrder.code,
                    "line_items": [],
                    "shipping_method": shippingType,
                    "send_shipping_notification": false,
                    "address_to": {
                        "first_name": firstName,
                        "last_name": lastName,
                        "email": printervalOrder.customer.email,
                        "phone": printervalOrder.customer.phone,
                        "country": printervalOrder.country.iso,
                        "region": region,
                        "address1": printervalOrder.delivery_address,
                        "address2": printervalOrder.optional_address,
                        "city": city,
                        "zip": printervalOrder.zip_code
                    }
                }

                let profiles = [];
                let lineItems = [];
                const mapItemPrintProvider = {};

                if(validateItem(printervalOrder.items).validated) {

                    if (shippingType == 3) { // express priority order
                        loadingButton('#btnPostPrintifyOrder');
                        $scope.textNotify = 'Creating Product...';
                        safeApply();
                    }

                    for (let i = 0; i < printervalOrder.items.length; i++) {

                        const itemData = printervalOrder.items[i];
                        const itemDataCopy = angular.copy(printervalOrder.items[i]);
                        const { print_areas } = getPrintAreaData(itemData);

                        let lineItem = null;

                        if (shippingType == 3) { // express priority order

                            const printifyProduct = await createPrintifyProduct(itemData);

                            lineItem = {
                                "product_id": printifyProduct.data.id,
                                "variant_id": parseInt(itemData.printify_state.variant.id),
                                "quantity": parseInt(itemData.quantity)
                            };
                            

                        } else { // standard order

                            lineItem = {
                                "print_provider_id": parseInt(itemData.printify_state.printProvider.id),
                                "blueprint_id": parseInt(itemData.printify_state.blueprint.blueprint_id),
                                "variant_id": parseInt(itemData.printify_state.variant.id),
                                "print_areas": print_areas,
                                "quantity": parseInt(itemData.quantity)
                            };

                        }
                        lineItems.push(lineItem);
                        profiles.push(getSingleProfile(itemDataCopy));

                        mapItemPrintProvider[itemData.id] = 'PRINTIFY ' + lineItem.print_provider_id + ' ' + itemData.printify_state.printProvider.name;
                    }

                    if (shippingType == 3) { // express priority order
                        loadingButton('#btnPostPrintifyOrder');
                        $scope.textNotify = '';
                        safeApply();
                    }

                    printifyOrder.line_items = lineItems;

                    const param = {
                        title: 'Create Order',
                        customText: 'Post order to Printify!',
                        confirmButtonText: 'Ok',
                        cancelButtonText: 'Back'
                    };

                    swal({
                        title: param.title,
                        html: param.customText,
                        type: "warning",
                        showConfirmButton: true,
                        showCancelButton: true,
                        confirmButtonText: param.confirmButtonText,
                        cancelButtonText: param.cancelButtonText
                    }).then(async function (isConfirm) 
                    {
                        if (isConfirm.value) {
                           
                            loadingButton('#btnPostPrintifyOrder');

                            $scope.textNotify = 'Saving Profile...';
                            safeApply();
                            await postProfiles(profiles);

                            $scope.textNotify = 'Saving Zipcode DB...';
                            safeApply();
                            await postZipcode(printifyOrder);

                            postToPrintify(printifyOrder, {mapItemPrintProvider});
                            $scope.textNotify = 'Fulfill Order...';
                            safeApply();

                        } else {
                            console.log(printifyOrder, profiles);
                            stopLoadingButton('#btnPostPrintifyOrder');
                            $scope.textNotify = '';
                            safeApply();
                        }

                    });

                } else {
                    document.getElementById("errorModalPrintify").style.display = "block";
                }
            }

            $scope.checkShowPrintify = function (orderItems) {
                return orderItems.some(item => item.printing_code == 'printify' && item.resource_id && item.store_id);
            }

            $scope.getInfoPrintifyOrder = async function (orderItems) {
                $scope.printifyOrderInfos = [];
                $scope.printifyProductInfos = [];
                let data;
                for (let i = 0; i < orderItems.length; i++) {
                    if (orderItems[i].printing_code == 'printify' && orderItems[i].resource_id && orderItems[i].store_id) {
                        data = {
                            method: 'GET',
                            end_point: '/v1/shops/' + orderItems[i].store_id + '/orders/' + orderItems[i].resource_id + '.json',
                            shop_id: orderItems[i].store_id
                        }
                        const params = new URLSearchParams(data).toString();
                        const requestObj = $scope.buildLocaleData('/print-suppliers/printify/api?' + params, {}, '');
                        await $scope.axiosClient.get(requestObj.url)
                            .then(async (response) => {
                                $scope.printifyOrderInfos.push(response.data);
                                if (response.data) {
                                    data = {
                                        method: 'GET',
                                        end_point: '/v1/shops/' + orderItems[i].store_id + '/products/' + response.data.line_items[0].product_id + '.json',
                                        shop_id: orderItems[i].store_id
                                    }
                                    const requestProductInfo = $scope.buildLocaleData('/print-suppliers/printify/api?' + new URLSearchParams(data).toString(), {}, '')
                                    await $scope.axiosClient.get(requestProductInfo.url)
                                        .then((response) => {
                                            if (response.data) {
                                                $scope.printifyProductInfos.push(response.data);
                                            }
                                        })
                                    safeApply();
                                }
                            });
                    }
                }
                document.getElementById("infoModalPrintify").style.display = "block";
            }

            $scope.formatCentToDollar = function (cent) {
                return (cent / 100).toFixed(2);
            }

            function ffErrorCallback() {
                stopLoadingButton('#btnPostPrintifyOrder');
                $scope.textNotify = '';
                safeApply();
            }

            function postToPrintify(printifyOrder, additionalData = {})
            {
                toastr.options.positionClass = "toast-bottom-left";
                
                const paramsData = {
                    method: 'POST',
                    end_point: '/v1/shops/' + $scope.printifyAccount.shop_id + '/orders.json',
                    shop_id: $scope.printifyAccount.shop_id
                };

                if (printifyOrder.shipping_method == 3) {
                    paramsData.end_point = '/v1/shops/' + $scope.printifyAccount.shop_id + '/orders/express.json';
                }

                const params = new URLSearchParams(paramsData).toString();
                const requestObj = $scope.buildLocaleData('/print-suppliers/printify/api?' + params, {}, $scope.fulFillLocale);

                $scope.axiosClient.post(requestObj.url, {params: printifyOrder}).then(response => {

                    if (response.data.id || response.data.data[0].id) {

                        $scope.textNotify = 'Logging after fulfill (ID: ' + response.data.id + ')...';

                        if (Array.isArray(response.data.data)) {
                            // Code to handle array response.data

                            const prms = [];
                            for (let i = 0; i < response.data.data.length; i++) 
                            {
                                prms.push(new Promise((resolve) => {
                                    afterFulfillAction(printifyOrder, response.data.data[i], additionalData).then(r => {
                                        resolve(r);
                                    });
                                }));
                            }
                            
                            Promise.all(prms).then(r => {
                                $scope.textNotify = '';
                                toastr.success('Successfully');
                                $('#modalFulfillPrintify').modal('hide');
                            });

                        } else {
                            // Code to handle non-array response.data
                            afterFulfillAction(printifyOrder, response.data, additionalData).then(r => {

                                if (r.data.status == 'successful') {
    
                                    $scope.textNotify = 'Get Printify Order Info...';

                                    // checking cost vs estimate
                                    getPrintifyOrderInfo(response.data.id).then(response => {
                                        const totalCost = (response.data.total_price + response.data.total_shipping + response.data.total_tax) / 100;
                                        if ($scope.printifyCurrentOrder.amount && totalCost > $scope.printifyCurrentOrder.amount) {
                                            toastr.warning('Giá vốn của đơn hàng ' + $scope.printifyCurrentOrder.code + ' cao hơn giá trị đơn hàng. Bạn cần xác nhận lại giá vốn trước khi xác nhận đơn hàng.');
                                        }

                                        $scope.textNotify = '';
                                        toastr.success('Successfully');
                                    
                                        $('#modalFulfillPrintify').modal('hide');
                                    });
    
                                } else {
    
                                    ffErrorCallback();
                                    toastr.error('Cannot verify resource_id, please check carefully this order!');
    
                                }
    
                            });

                        }

                    } else {
                        toastr.warning('Whoop! Something went wrong.');
                        toastr.warning($scope.getFailFulfillMessage('printify'));
                        toastr.warning(JSON.stringify(response.data));
                    }

                    stopLoadingButton('#btnPostPrintifyOrder');
                    safeApply();

                }).catch(function (error) {
                    if(error.response) {
                        if(error.response.data.status === 'error') {
                            toastr.error(error.response.data.errors.reason);
                        }
                    }

                    stopLoadingButton('#btnPostPrintifyOrder');
                    safeApply();
                });
            }

            function getPrintifyOrderInfo(printifyOrderId)
            {
                const paramsData = {
                    method: 'GET',
                    end_point: '/v1/shops/' + $scope.printifyAccount.shop_id + '/orders/' + printifyOrderId + '.json',
                    shop_id: $scope.printifyAccount.shop_id
                };

                const params = new URLSearchParams(paramsData).toString();
                const requestObj = $scope.buildLocaleData('/print-suppliers/printify/api?' + params, {}, $scope.fulFillLocale);

                return $scope.axiosClient.get(requestObj.url);
            }

            function logPrintifyFulFill(printifyOrder, isLogData = false) 
            {
                let logData;

                if (!isLogData) {
                    printifyOrder.printify_shop_id = $scope.printifyAccount.shop_id;
                    logData = {
                        actor_email: user_email,
                        target_id: $scope.printifyCurrentOrder.id,
                        data: printifyOrder
                    };

                } else {
                    logData = printifyOrder;
                }
                logData.printer = 'printify';

                const requestObj = $scope.buildLocaleData('/print-suppliers/fulfill/log', logData, $scope.fulFillLocale);
                $http.post(requestObj.url, requestObj.params).then(() => {});

            }

            let loadingButton = function (selector, text = 'Processing...') {
                $(selector).attr('dt-text', $(selector).text());
                $(selector).text(text);
                $(selector).attr("disabled", true);
            }

            let stopLoadingButton = function (selector) {
                $(selector).html($(selector).attr('dt-text'));
                $(selector).attr("disabled", false);
            }

            function postZipcode(printOrder) {

                return new Promise(function (resolve, reject) {
                    let zipcodeData = {
                        country_id: $scope.printifyCurrentOrder.country_id,
                        code: printOrder.address_to.zip,
                        city: printOrder.address_to.city,
                        region: printOrder.address_to.region
                    };
                    let requestObj = $scope.buildLocaleData('/print-suppliers/zipcode', zipcodeData, $scope.fulFillLocale);

                    $http.post(requestObj.url, requestObj.params).then(function(response) {
                        resolve(response.data.data);
                    }, function (error) {
                        resolve(error);
                    });
                })
                
            }

            function postProfiles(profiles) {
                let errMessage = 'Error save profile. Please contact technical team.';

                const promisePostProfile = new Promise(function (resolve, reject) {
                    const requestObj = $scope.buildLocaleData('/print-suppliers/profile', profiles, $scope.fulFillLocale);

                    let postProfileUrl = requestObj.url;
                    /* try
                    {
                        const urlObject = new URL('https://printerval.com' + requestObj.url);

                        urlObject.hostname = 'direct.' + urlObject.hostname;

                        postProfileUrl = urlObject.toString();

                    } catch (error) {
                        console.warn(error);
                    } */

                    $http.post(postProfileUrl, requestObj.params).then(function(response) {
                        if (response.data.status === "successful") {
                            resolve(response.data.data);
                        } else {
                            ffErrorCallback();
                            toastr.error(errMessage);
                            reject();
                        }
                    });
                });

                let promises = [promisePostProfile];

                if ($scope.needSaveTemplate) {
                    const promisePostTemplate = new Promise(function (resolve, reject) {
                        const requestObj = $scope.buildLocaleData('/print-suppliers/printify/fulfill-template', profiles, $scope.fulFillLocale);
                        $http.post(requestObj.url, requestObj.params).then(function(response) {
                            resolve();
                        });
                    });
                    promises.push(promisePostTemplate);
                }

                return Promise.all(promises);
            }

            function validateItem(items) {
                let validated = true;
                let messages = {};

                for (let i = 0; i < items.length; i++) {
                    const itemData = items[i];
                    messages[itemData.product_sku_id] = [];

                    if(typeof itemData.printify_state == 'undefined') {
                        messages[itemData.product_sku_id].push(itemData.name + '|| Missing Printify Data.');
                        validated = false;
                        continue;
                    }

                    let hasDesign = false;
                    for (const key in itemData.printify_state.designs) {
                        if(
                            typeof itemData.printify_state.printAreas != 'undefined'
                            && itemData.printify_state.designs[key] 
                            && isValidHttpUrl(itemData.printify_state.designs[key])
                            && itemData.printify_state.printAreas.includes(key)
                        ) {
                            hasDesign = true;
                            break;
                        }
                    }

                    if(
                        typeof itemData.printify_state.blueprint == 'undefined' || 
                        !itemData.printify_state.blueprint ||
                        !itemData.printify_state.blueprint.id
                    ) {
                        validated = false;
                        messages[itemData.product_sku_id].push(itemData.name + '|| Missing blueprint.');
                    }
                    if(
                        typeof itemData.printify_state.printProvider == 'undefined' || 
                        !itemData.printify_state.printProvider ||
                        !itemData.printify_state.printProvider.id
                    ) {
                        validated = false;
                        messages[itemData.product_sku_id].push(itemData.name + '|| Missing print provider.');
                    }
                    if(!hasDesign) {
                        validated = false;
                        messages[itemData.product_sku_id].push(itemData.name + '|| Missing design.');
                    }

                }

                $scope.pritifyState.messages = messages;

                return {
                    validated,
                    messages
                };
            }

            $scope.chooseColor = function (option, printOrderItem) 
            {
                printOrderItem.printify_state.color_id = option.id;
                printOrderItem.printify_state.selectedColor = option;
                printOrderItem.printify_state.options.color = option.id;

                $scope.changeVariantOption(printOrderItem);
            }

            $scope.chooseDesign = function (design, printOrderItem, option) {
                /* for (let i = 0; i < printOrderItem.printify_state.patternDesigns.length; i++) {
                    printOrderItem.printify_state.patternDesigns[i].selected = false;
                }*/
                // design.selected = true;

                if (!design.is_design_comfirm) {
                    toastr.error('Design is not confirmed');
                    return;
                }

                printOrderItem.printify_state.designs[option] = design.url;
                $scope.changeDesignUrl(option, printOrderItem);
            }

            $scope.checkOpenSearch = function(printOrderItem) {
                return $scope.pritifyState.searchingFor && $scope.pritifyState.searchingFor == printOrderItem.id;
            }

            $scope.uploadImages = async function(files, printOrderItem, printArea) {
                let supportedFilesType = ['image/png', 'image/jpg', 'image/jpeg', 'image/gif'];
                let supportedFilesExtensions = ['jpg', 'jpeg', 'png', 'gif'];

                if (files) {
                    try {

                        let imagesUploaded = [];
                        let imageFile = null;
                        if (files && files.length) {
                            imageFile = files[0];
                            let fileExtension = imageFile.name.split('.').pop();
                            fileExtension = fileExtension.toLowerCase();
                            if (supportedFilesExtensions.includes(fileExtension) &&
                                supportedFilesType.includes(
                                    imageFile.type)) {
                                printOrderItem.uploading = true;
                                imagesUploaded = await $scope.uploads(files);
                            } else {
                                toastr.error('Error! format supported: jpg, jpeg, png, gif');
                            }
                        }

                        printOrderItem.uploading = false;
                        if (imagesUploaded.length) {
                            $scope.$applyAsync(function() {
                                let imageUrl = imagesUploaded.pop();

                                printOrderItem.printify_state.designs[printArea] = imageUrl;
                                printOrderItem.printify_state.currentDesignUrl = imageUrl;

                                resetPosition(printArea, printOrderItem);
                            });
                        }

                    } catch (error) {
                        console.log(error);
                        toastr.error('Error upload images!');
                        printOrderItem.uploading = false;
                    }
                }
            };

            $scope.uploads = function (files) {
                if (typeof googleCloudStorageBucket !== 'undefined') {
                    baseFileManagerUrl = googleCloudStorageBucket;
                }
                return new Promise(function(resolve, reject) {
                    Upload.upload({
                        url: baseFileManagerUrl + '/upload',
                        data: {upload: files, type: 'design'}
                    }).then(function (resp) {
                        if (resp.data.status == 'successful') {
                            let upload = resp.data.upload;
                            resolve(upload);
                        } else {
                            reject(0);
                        }
                    }, function (resp) {
                        reject(0);
                    }, function (evt) {
                        let progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
                        $scope.progressPercentage = progressPercentage;
                    });
                });
            };

            $scope.getDisplayPosition = function (item, option) {
                try {
                    if(
                        typeof item.printify_state.designPositions != "undefined" && item.printify_state.designPositions
                        && typeof item.printify_state.designPositions.position != 'undefined' && item.printify_state.designPositions.position
                    ) {
                        let data = item.printify_state.designPositions.position[option.toLowerCase().split(' ')[0]];
                        let text = [];
                        for (const key in data) {
                            if (Object.hasOwnProperty.call(data, key)) {
                                text.push(key.toUpperCase() + ': ' + parseFloat(data[key]).toFixed(2));
                            }
                        }
                        return text.join(', ');
                    }
                } catch (error) {
                    console.warn(error);
                }
            }

            /* Design Location */
            $scope.designCanvasObject = {};
            $scope.Math = window.Math;
            var initInfor = {};
            var canvas = null;
            var frame = {padding: 50}

            function getFitDimension(obj) {
                if (!obj.width || !obj.height) return null;

                let fit = 'height';
                if (obj.width - obj.height < 0) {
                    fit = 'width';
                }

                return fit;
            }

            $scope.parseInfo = function (value, key) {
                value = parseFloat(value);
                let defaultValue = parseFloat(initInfor[key]);
                
                if(key === 'scale') {
                    let ratio = 100 / defaultValue;
                    return ratio * value / 100;
                }

                if(key === 'top' || key === 'left') {
                    
                    let designCanvasWidth = $scope.designCanvasObject.width * $scope.designCanvasObject.scaleY;
                    let designCanvasHeight = $scope.designCanvasObject.height * $scope.designCanvasObject.scaleY;

                    let ratio = 0;

                    if(typeof $scope.designCanvasObject.getCenterPoint != "undefined") {
                        let center = $scope.designCanvasObject.getCenterPoint();

                        if(key === 'top') {
                            let direct = (defaultValue - center.y > 0) ? -1 : 1;
                            let delta = Math.abs(defaultValue - center.y);
                            ratio = (direct * delta / frame.height);

                        } else if (key === 'left') {
                            let direct = (defaultValue - center.x > 0) ? -1 : 1;
                            let delta = Math.abs(defaultValue - center.x);
                            ratio = (direct * delta / frame.width);

                        }
                    }

                    return ratio;
                }
                
            }

            $scope.openEditDesignModal = function (designSrc, option, item) {
                let blueprintId = null;
                let providerId = null;

                try {
                    blueprintId = item.printify_state.blueprint.blueprint_id;
                    providerId = item.printify_state.printProvider.id;
                } catch (error) {
                    toastr.warning('Missing blueprintId or providerId!');
                    return;
                }

                $scope.currentDesignItem = item;
                $scope.loadingDesign = true;
                
                $("#DesignModalPrintify").show();
                if(canvas) {
                    canvas.clear();
                    canvas.dispose();
                }

                let params = new URLSearchParams({
                    end_point: 'blueprints/' + blueprintId + '/' + providerId,
                    base_api: 'https://printify.com/api/v1/',
                    shop_id: $scope.printifyAccount.shop_id
                }).toString();

                const requestObj = $scope.buildLocaleData('/print-suppliers/printify/api?' + params, {}, $scope.fulFillLocale);
                $scope.axiosClient.get(requestObj.url).then(response => {

                    let options = response.data.print_provider.options;
                    let sizes = null;

                    let sizeFulfill = item.printify_state.sizes.find((size) => {
                        return size.id == item.printify_state.size_id;
                    });

                    for (let i = 0; i < options.length; i++) {
                        const providerOption = options[i];
                        if (providerOption.items) {
                            for (const key in item.printify_state.options) {
                                if (Object.hasOwnProperty.call(item.printify_state.options, key)) {
                                    const choosedOption = item.printify_state.options[key];
                                    const matchOption = providerOption.items.find((pOitem) => {
                                        return parseInt(pOitem.id) == parseInt(choosedOption);
                                    });

                                    if (matchOption && matchOption.sizes && matchOption.sizes.length) {
                                        sizes = matchOption.sizes;
                                    }
                                }
                            }
                        }
                    }

                    if(sizes) {

                        let placeholders = null;
                        let prints = response.data.print_provider.prints;
                        if(prints && prints.length) {
                            placeholders = prints.pop().placeholders;
                        }

                        option = option.toLowerCase();
                        if(option === 'front side' || option === 'back side') {
                            option = option.split(' ')[0];
                        }

                        let domId = null;
                        if(option && placeholders) {
                            let placeholder = placeholders.find((placeholder) => {
                                return placeholder.position == option;
                            });
                            domId = placeholder.dom_id;
                        }

                        if(domId) {

                            if(domId.length) domId = domId.pop();
                            let size = sizes.find((item) => {
                                return item.placeholder_id == domId; 
                            });

                            frame.width = frame.origin_width = size.width;
                            frame.height = frame.origin_height = size.height;
                            frame.ratio = size.width / size.height;

                            if(typeof item.printify_state.designPositions == 'undefined' || !item.printify_state.designPositions)
                                item.printify_state.designPositions = {
                                    frames: {}
                                };

                            item.printify_state.designPositions.frames[option] = frame;
                            $scope.currentDesignOption = option;
                        }

                    }

                    let fitDimension;
                    if (typeof frame.width != 'undefined' && typeof frame.height != 'undefined' && frame.width && frame.height) {
                        // calculate canvas size
                        let contentBlock = $('#DesignModalPrintify .error-modal-content');
                        let canvasDimensions = {
                            width: contentBlock.width(),
                            height: $(window).height() - 230,
                            padding: 50
                        }

                        canvas = this.__canvas = new fabric.Canvas('c');
                        canvas.setHeight(canvasDimensions.height);
                        canvas.setWidth(canvasDimensions.width);

                        canvas.setBackgroundColor({
                            source: '/modules/print-suppliers/images/transparent.png',
                            repeat: 'repeat'
                        }, function () {
                            canvas.renderAll();
                        });

                        let borderColor = null;
                        try {
                            let bgColor = item.printify_state.selectedColor.colors[0].hex;
                            borderColor = invertColor(bgColor, true);
                            canvas.setBackgroundColor(bgColor, canvas.renderAll.bind(canvas));
                        } catch (error) {

                        }

                        fitDimension = 'width';
                        // đưa chiều rộng về bằng nhau giữa khung và canvas
                        let tempWidth = canvasDimensions['width'];
                        let tempHeight = tempWidth / frame.ratio;
                        // nếu chiều cao lớn hơn chiều cao của casvas cần căn theo chiều cao
                        if (tempHeight > canvasDimensions.height) {
                            fitDimension = 'height';
                        }

                        frame[fitDimension] = canvasDimensions[fitDimension] - 2 * canvasDimensions.padding;
                        // tính chiều còn lại theo tỉ lệ
                        if (fitDimension === 'width') {
                            frame['height'] = frame['width'] / frame.ratio;
                        } else {
                            frame['width'] = frame['height'] * frame.ratio;
                        }

                        // căn frame vào giữa canvas
                        frame.top = canvasDimensions.height / 2 - frame.height / 2;
                        frame.left = canvasDimensions.width / 2 - frame.width / 2;

                        let rect = new fabric.Rect({ // draw frame
                            top: frame.top,
                            left: frame.left,
                            width: frame.width,
                            height: frame.height,
                            fill: '',
                            stroke: (borderColor) ? borderColor : '#333',
                            strokeWidth: 1,
                            strokeDashArray: [10, 5],
                            selectable: false
                        });
                        canvas.add(rect);

                        // draw design
                        fabric.Image.fromURL(designSrc, function (oImg) {

                            $scope.loadingDesign = false;

                            safeApply();

                            oImg.id = 'designImage';
                            ['ml', 'mb', 'mr', 'mt'].forEach(control => {
                                oImg.setControlVisible(control, false);
                            });
                            oImg.borderColor = '#007bff';
                            oImg.cornerColor = '#007bff';
                            oImg.transparentCorners = false;

                            // đã có chỉ số
                            if (
                                typeof item.printify_state.designPositions != 'undefined' &&
                                typeof item.printify_state.designPositions.positionPrinterval != 'undefined'
                                && typeof item.printify_state.designPositions.positionPrinterval[option] != 'undefined'
                                && item.printify_state.designPositions.positionPrinterval[option]
                            ) {
                                let positionInfo = item.printify_state.designPositions.positionPrinterval[option];

                                oImg.scaleToWidth(frame['width']);

                                oImg.set({
                                    left: frame.left + frame.width / 2 - (oImg.width * oImg.scaleY / 2),
                                    top: frame.top + (frame.height / 2) - (oImg.height * oImg.scaleY / 2)
                                });

                                initInfor.top = frame.top;
                                initInfor.left = frame.left;
                                initInfor.scale = oImg.scaleX;
                                initInfor.angle = oImg.angle;

                                oImg.set({
                                    left: positionInfo.left,
                                    top: positionInfo.top,
                                    scaleX: positionInfo.scaleX,
                                    scaleY: positionInfo.scaleY,
                                    angle: positionInfo.angle
                                });

                                oImg.setCoords();

                            } else {

                                // chưa có chỉ số
                                // luôn fit theo width giống prinfity
                                oImg.scaleToWidth(frame['width']);

                                oImg.set({
                                    left: frame.left + frame.width / 2 - (oImg.width * oImg.scaleY / 2),
                                    top: frame.top + (frame.height / 2) - (oImg.height * oImg.scaleY / 2)
                                });

                                initInfor.top = frame.top;
                                initInfor.left = frame.left;
                                initInfor.scale = oImg.scaleX;
                                initInfor.angle = oImg.angle;

                            }

                            canvas.add(oImg);
                            canvas.setActiveObject(oImg);

                            $scope.designCanvasObject = oImg;

                            updateFrontValueDesign(oImg);

                            safeApply();
                        });

                        canvas.renderAll();

                        observe('object:moving');
                        observe('object:scaling');
                        observe('object:rotating');
                        observe('object:skewing');
                        observe('object:moved');
                        observe('object:scaled');
                        observe('object:rotated');
                        observe('object:skewed');
                    }

                });
    
            }

            function invertColor(hex, bw) {
                if (hex.indexOf('#') === 0) {
                    hex = hex.slice(1);
                }
                // convert 3-digit hex to 6-digits.
                if (hex.length === 3) {
                    hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
                }
                if (hex.length !== 6) {
                    console.warn('Invalid HEX color.');
                    return '#ffffff';
                }
                let r = parseInt(hex.slice(0, 2), 16),
                    g = parseInt(hex.slice(2, 4), 16),
                    b = parseInt(hex.slice(4, 6), 16);
                if (bw) {
                    return (r * 0.299 + g * 0.587 + b * 0.114) > 186
                        ? '#000000'
                        : '#FFFFFF';
                }
                // invert color components
                r = (255 - r).toString(16);
                g = (255 - g).toString(16);
                b = (255 - b).toString(16);
                // pad each with zeros and return

                return "#" + padZero(r) + padZero(g) + padZero(b);
            }

            function padZero(str, len) {
                len = len || 2;
                const zeros = new Array(len).join('0');
                return (zeros + str).slice(-len);
            }

            function observe(eventName) {
                canvas.on(eventName, function(opt){
                    canvas.getObjects().forEach(function(o) {
                        if(o.id === 'designImage') {
                            updateFrontValueDesign(o);
                        }
                    })
                });
            }

            function updateFrontValueDesign(o) {
                document.getElementById('designAngle').innerHTML = o.angle.toFixed(3);
                document.getElementById('designX').innerHTML = $scope.parseInfo(o.left, 'left').toFixed(5);
                document.getElementById('designY').innerHTML = $scope.parseInfo(o.top, 'top').toFixed(5);
                document.getElementById('designScale').innerHTML = ($scope.parseInfo(o.scaleX, 'scale') * 100).toFixed(2);

                let designDimensions = getDesignDimensions(o);
                document.getElementById('designWidth').value = designDimensions.width.toFixed(2);
                document.getElementById('designHeight').value = designDimensions.height.toFixed(2);

                let top = getDesignTop(o);
                document.getElementById('designTop').value = top.toFixed(2);
            }

            $scope.applyDesignPosition = function () {
                canvas.getObjects().forEach(function(o) {
                    if(o.id === 'designImage') {

                        let printifyPosition = {
                            x: $scope.parseInfo(o.left, 'left'),
                            y: $scope.parseInfo(o.top, 'top'),
                            scale: $scope.parseInfo(o.scaleX, 'scale'),
                            angle: o.angle.toFixed(2)
                        }

                        let printervalPosition = {
                            left: o.left,
                            top: o.top,
                            scaleX: o.scaleX,
                            scaleY: o.scaleY,
                            angle: o.angle,
                            initInfor: initInfor
                        }

                        if(typeof $scope.currentDesignItem.printify_state.designPositions.position == 'undefined') {
                            $scope.currentDesignItem.printify_state.designPositions.position = {};
                        }

                        if(typeof $scope.currentDesignItem.printify_state.designPositions.positionPrinterval == 'undefined') {
                            $scope.currentDesignItem.printify_state.designPositions.positionPrinterval = {};
                        }

                        $scope.currentDesignItem.printify_state.designPositions.position[$scope.currentDesignOption] = printifyPosition;
                        $scope.currentDesignItem.printify_state.designPositions.positionPrinterval[$scope.currentDesignOption] = printervalPosition;

                        safeApply();

                        $('#DesignModalPrintify').fadeOut();

                    }
                })
            }

            $scope.changeDesign2CenterV = function () {
                canvas.getObjects().forEach(function(o) {
                    if(o.id === 'designImage') {
                        o.centerV();
                        o.setCoords();
                        updateFrontValueDesign(o);
                    }
                })
            }
            $scope.changeDesign2CenterH = function () {
                canvas.getObjects().forEach(function(o) {
                    if(o.id === 'designImage') {
                        o.centerH();
                        o.setCoords();
                        updateFrontValueDesign(o);
                    }
                })
            }
            $scope.changeDesign2Left = function () {
                canvas.getObjects().forEach(function(o) {
                    if(o.id === 'designImage') {
                        let coords = o.getCoords();
                        let minX = null;
                        for (let i = 0; i < coords.length; i++) {
                            if(!minX) minX = coords[i].x;
                            if(coords[i].x < minX) minX = coords[i].x;
                        }

                        let delta = minX - frame.left;
                        o.left = o.left - delta;
                        o.setCoords();
                        canvas.renderAll();
                        updateFrontValueDesign(o);
                    }
                })
            }
            $scope.changeDesign2Right = function () {
                canvas.getObjects().forEach(function(o) {
                    if(o.id === 'designImage') {
                        let coords = o.getCoords();
                        let maxX = null;
                        for (let i = 0; i < coords.length; i++) {
                            if(!maxX) maxX = coords[i].x;
                            if(coords[i].x > maxX) maxX = coords[i].x;
                        }

                        let delta = frame.left + frame.width - maxX;
                        o.left = o.left + delta;
                        o.setCoords();
                        canvas.renderAll();
                        updateFrontValueDesign(o);
                    }
                })
            }
            $scope.changeDesign2Top = function () {
                canvas.getObjects().forEach(function(o) {
                    if(o.id === 'designImage') {
                        let coords = o.getCoords();
                        let minY = null;
                        for (let i = 0; i < coords.length; i++) {
                            if(!minY) minY = coords[i].y;
                            if(coords[i].y < minY) minY = coords[i].y;
                        }

                        let delta = minY - frame.top;
                        o.top = o.top - delta;
                        o.setCoords();
                        canvas.renderAll();
                        updateFrontValueDesign(o);
                    }
                })
            }
            $scope.changeDesign2Bottom = function () {
                canvas.getObjects().forEach(function(o) {
                    if(o.id === 'designImage') {
                        let coords = o.getCoords();
                        let maxY = null;
                        for (let i = 0; i < coords.length; i++) {
                            if(!maxY) maxY = coords[i].y;
                            if(coords[i].y > maxY) maxY = coords[i].y;
                        }

                        let delta = frame.top + frame.height - maxY;
                        o.top = o.top + delta;
                        o.setCoords();
                        canvas.renderAll();
                        updateFrontValueDesign(o);
                    }
                })
            }
            $scope.resetDesignPosition = function () {
                canvas.getObjects().forEach(function(o) {
                    if(o.id === 'designImage') {

                        o.rotate(0);
                        o.setCoords();
                        o.scaleToWidth(frame.width);
                        o.setCoords();
                        o.center();
                        o.setCoords();

                        updateFrontValueDesign(o);
                    }
                })
            }

            function setDesignDimensions(width, height, type) {
                canvas.getObjects().forEach(function(o) {
                    if(o.id === 'designImage') {

                        let frameScale =  frame.width / frame.origin_width;

                        let scale;
                        if(type === 'width') {
                            scale = (width * frameScale) / o.width;
                        } else {
                            scale = (height * frameScale) / o.height;
                        }

                        if(scale) {
                            o.scaleX = scale;
                            o.scaleY = scale;
                            o.setCoords();
                            canvas.renderAll();
                            updateFrontValueDesign(o);
                        }
                    }
                });
            }

            function distanceFrom2Points(x1, y1, x2, y2) {
                let a = x1 - x2;
                let b = y1 - y2;
                return Math.sqrt( a*a + b*b );
            }

            function getDesignDimensions(o) {
                let returnData = {width: 0, height: 0};
                let coords = o.getCoords();

                let width = distanceFrom2Points(coords[1].x, coords[1].y, coords[0].x, coords[0].y);
                let height = distanceFrom2Points(coords[3].x, coords[3].y, coords[0].x, coords[0].y);
                let frameScale =  frame.width / frame.origin_width;

                returnData.width = (width / frameScale) / 10;
                returnData.height = (height / frameScale) / 10;

                return returnData;
            }

            function getDesignTop(o) {
                let coords = o.getCoords();

                let minY = null;
                for (let i = 0; i < coords.length; i++) {
                    if(!minY) minY = coords[i].y;
                    if(coords[i].y < minY) minY = coords[i].y;
                }

                let delta = minY - frame.top;
                return delta / frame.height * 100;
            }

            let typingDimensionsTimeout = null;
            $scope.changeDesignDimensions = function(type) {
                if(typingDimensionsTimeout) clearTimeout(typingDimensionsTimeout);
                typingDimensionsTimeout = setTimeout(() => {
                    let width = document.getElementById('designWidth').value;
                    let height = document.getElementById('designHeight').value;
                    
                    if(width && height) {
                        width = width * 10;
                        height = height * 10;
                        
                        if(width < (frame.origin_width * 5) && height < (frame.origin_height * 5)) {
                            setDesignDimensions(width, height, type);
                        } else {
                            /* canvas.getObjects().forEach(function(o) {
                                if(o.id === 'designImage') {
                                    updateFrontValueDesign(o);
                                }
                            }); */
                        }
                    }
                }, 500);
            }

            let typingTopPercentTimeout = null;
            $scope.changeDesignTop = function() {
                let topPercent = document.getElementById('designTop').value;
                if(typingTopPercentTimeout) clearTimeout(typingTopPercentTimeout);
                typingTopPercentTimeout = setTimeout(() => {
                    canvas.getObjects().forEach(function(o) {
                        if(o.id === 'designImage') {
                            let coords = o.getCoords();
                            let minY = null;
                            for (let i = 0; i < coords.length; i++) {
                                if(!minY) minY = coords[i].y;
                                if(coords[i].y < minY) minY = coords[i].y;
                            }

                            let delta = Math.abs(minY - o.top);
                            let topDistance = ((frame.height / 100) * topPercent);

                            o.top = frame.top + topDistance + delta;

                            o.setCoords();
                            canvas.renderAll();
                            updateFrontValueDesign(o);
                        }
                    })
                }, 600);
            }

            $scope.createDesignJob = (product) => 
            {
                let localCode = localePrefix;
                if (typeof localCode === 'undefined' || localCode === '') {
                    localCode = defaultLocale;
                }
                let regex = /Size:\s*(.*?)\s*,/;
                let match = regex.exec(product.product_name);
                if (match) {
                    product.size = match[1];
                }

                if (localCode == 'central') {
                    localCode = $scope.fulFillLocale;
                }
                
                const designData = {
                    products: [product],
                    product_id: product.product_id,
                    creator_email: user.email,
                    is_custom: product.is_custom_design,
                    note: product.newDesignJob ? product.newDesignJob.note : null,
                    local_code: localCode,
                    configurations: product.configurations,
                    order_id: product.order_id,
                    order_item_id: product.id,
                    is_redesign: product.newDesignJob.is_redesign,
                    job_type: product.newDesignJob ? product.newDesignJob.job_type : '2D',
                };
                let requestObj = $scope.buildLocaleData("/service/pod/design-job/create", designData, $scope.fulFillLocale);
                if (localePrefix == 'central') { 
                    requestObj = { url: "/service/pod/design-job/create", params: designData};
                }
                $http.post(requestObj.url, requestObj.params).then((res) => {
                    if ( res.data.status === 'successful') {
                        product.designJob = res.data.result;
                        toastr.success('Send request design successful');
                    } else {
                        toastr.error('Error when create design job!');
                    }
                })

            }
                 
            const checkAvailableDesign = (item) => {

                let localCode = localePrefix;
                if (typeof localCode === 'undefined' || localCode === '') {
                    localCode = defaultLocale;
                }

                if (localCode == 'central') {
                    localCode = $scope.fulFillLocale;
                }

                const data = {
                    product_id: item.product_id,
                    locale: localCode
                };

                const requestObj = $scope.buildLocaleData('/service/pod/product/design-available', data, $scope.fulFillLocale);
                return $http.get(requestObj.url, { params: requestObj.params }).then((res) => {
                    if ( res.data.status === 'successful') {
                        item.designAvailable = res.data.result;
                    }else {
                        item.designAvailable = null;
                    }
                })
            }

            async function afterFulfillAction(printifyOrderPayload, printifyOrderResponse, additionalData = {}) {
                // log
                logPrintifyFulFill(printifyOrderPayload);
                logPrintifyFulFill({
                    actor_email: user_email,
                    target_id: $scope.printifyCurrentOrder.id,
                    event_type: 'PRINTIFY-ORDER-RESPONSE',
                    data: printifyOrderResponse
                }, true);

                // load order detail
                let printifyOrderId = printifyOrderResponse.id;
                let requestObj = $scope.buildLocaleData('/print-suppliers/printify/order-detail', {
                    order_id: printifyOrderId,
                    shop_id: $scope.printifyAccount.shop_id
                }, $scope.fulFillLocale);
                
                let printifyResponse = await $http.get(requestObj.url, {
                    params: requestObj.params
                });

                let productPrintifyIds = [];
                if (typeof printifyResponse.data.line_items !== 'undefined' && printifyResponse.data.line_items.length) {
                    for (let i = 0; i < printifyResponse.data.line_items.length; i++) {
                        productPrintifyIds.push(printifyResponse.data.line_items[i].product_id);
                    }
                }

                // attach product id
                const orderMeta = {
                    order_id: $scope.printifyCurrentOrder.id,
                    resource_id: printifyOrderId,
                    key: 'printify_product_ids',
                    value: productPrintifyIds.join(','),
                    shop_id: $scope.printifyAccount.shop_id
                };

                if (additionalData && typeof additionalData.mapItemPrintProvider) {
                    orderMeta.print_provider = additionalData.mapItemPrintProvider;
                }

                requestObj = $scope.buildLocaleData('/print-suppliers/fulfill/attach-order-meta', orderMeta, $scope.fulFillLocale);
                
                return $http.post(requestObj.url, requestObj.params);

            }

            function safeApply() {
                if ($scope.$root.$$phase !== '$apply' && $scope.$root.$$phase !== '$digest') {
                    $scope.$apply();
                }
            }

            $scope.copyProfileData = function(orderItem)
            {
                try 
                {
                    const profile = getSingleProfile(orderItem);

                    $scope.copyToClipboard(JSON.stringify(profile));
                    toastr.success('Copied profile!');

                } catch (error) {
                    toastr.error('Error, cannot copy profile!');
                }
            }

            $scope.pasteProfileData = function(orderItem)
            {
                try {
                    navigator.clipboard.readText()
                    .then(text => {

                        // const text = `{"product_id":23947,"is_template_product":false,"product_sku_id":2301060,"order_id":4695,"order_item_id":4695,"options":{"artworks":{"front":{"extension":"jpg","url":"https://assets.printerval.com/2023/05/10/wallpaperflare-8029884d02286ee23e29e3cf4af9443c.jpg"},"back":{}},"color":"Fire Red/ Arctic White","type":"Jacket","size":null,"sku":{"id":2,"sku":2602024,"brand":"AWDis","product_type":"Jacket","style":"AWJH043","product_name":"VARSITY JACKET","color":"Fire Red/ Arctic White","size":"M","selected":true}},"type":"print-logistic"}`;

                        profile = JSON.parse(text);
                        applySingleProfile(profile, orderItem);
                    })
                    .catch(err => {
                        console.error('Failed to read clipboard contents: ', err);
                    });
                } catch (error) {
                    toastr.error('Error, cannot paste profile!');
                    toastr.error(error);
                }
            }

            const getSingleProfile = function(item)
            {
                const { simple_print_areas } = getPrintAreaData(item);

                return {
                    product_id: item.product_id,
                    is_template_product: isTemplateProduct(item.product_id),
                    product_sku_id: item.product_sku_id,
                    blueprint_id: item.printify_state.blueprint.blueprint_id,
                    print_provider_id: item.printify_state.printProvider.id,
                    variant_id: item.printify_state.variant.id,
                    order_id: $scope.printifyCurrentOrder.id,
                    order_item_id: item.id,
                    print_areas: simple_print_areas,
                    position: (typeof item.printify_state.designPositions != 'undefined') ? item.printify_state.designPositions : null,
                    options: item.printify_state.options
                    /* {
                        color_id: item.printify_state.color_id,
                        size_id: item.printify_state.size_id
                    } */
                };
            }

            const getPrintAreaData = function(itemData)
            {
                const print_areas = {};
                const simple_print_areas = {};
                for (const key in itemData.printify_state.designs) {
                    if (Object.hasOwnProperty.call(itemData.printify_state.designs, key)) {
                        if(
                            itemData.printify_state.designs[key] 
                            && isValidHttpUrl(itemData.printify_state.designs[key])
                            && itemData.printify_state.printAreas.includes(key)
                        ) {

                            if(isAjustedPosition(itemData, key)) {
                                const positionData = itemData.printify_state.designPositions.position[key.toLowerCase().split(' ')[0]];
                                print_areas[key.toLowerCase().split(' ')[0]] = [{
                                    "src": itemData.printify_state.designs[key],
                                    "scale": positionData.scale,
                                    "x": positionData.x,
                                    "y": positionData.y,
                                    "angle": positionData.angle
                                }];

                            } else {
                                print_areas[key.toLowerCase().split(' ')[0]] = itemData.printify_state.designs[key];
                            }
                            simple_print_areas[key.toLowerCase().split(' ')[0]] = itemData.printify_state.designs[key];

                        }
                            
                    }
                }

                return {
                    print_areas,
                    simple_print_areas
                }
            }

            const isAjustedPosition = function(itemData, key) {
                return typeof itemData.printify_state.designPositions != "undefined" &&
                    itemData.printify_state.designPositions != null &&
                    typeof itemData.printify_state.designPositions.position != "undefined" &&
                    itemData.printify_state.designPositions.position != null &&
                    typeof itemData.printify_state.designPositions.position[key.toLowerCase().split(' ')[0]] != "undefined"
            }

            const applySingleProfile = async function(profile, orderItem)
            {    
                const blueprint = {
                    data: null
                };

                const blueprintResponse = await $scope.getProfileBlueprint(profile.blueprint_id);                                                        
                if(blueprintResponse.result && blueprintResponse.result.length) {
                    blueprint.data = blueprintResponse.result[0];
                }

                if (typeof orderItem.printify_state == 'undefined' || !orderItem.printify_state) {
                    orderItem.printify_state = {};
                }

                orderItem.printify_state.blueprint = blueprint.data;
                orderItem.printify_state.loading = true;

                if(profile.options) 
                {

                    orderItem.printify_state.options = Object.keys(profile.options).reduce((newObj, key) => {
                        newObj[key] = String(profile.options[key]);
                        if (key == 'size') orderItem.printify_state.size_id = profile.options[key];
                        return newObj;
                    }, {});

                    if (profile.options.color_id) {
                        orderItem.printify_state.color_id = profile.options.color_id.toString();
                    }
                    if (profile.options.size_id) {
                        orderItem.printify_state.size_id = profile.options.size_id.toString();
                    }
                }

                if(profile.variant_id) {
                    orderItem.printify_state.variant_id = profile.variant_id;
                }

                if(profile.print_provider_id) {
                    orderItem.printify_state.print_provider_id = profile.print_provider_id;
                }

                if(profile.print_areas) 
                {
                    let mapDesigns = {};
                    for (const key in profile.print_areas) {
                        if (Object.hasOwnProperty.call(profile.print_areas, key)) {
                            const url = profile.print_areas[key];

                            let dKey = $scope.capitalizeFirstLetter(key);

                            if (dKey === 'Front' || dKey === 'Back') { dKey = dKey + ' side' }

                            mapDesigns[dKey] = url;
                        }
                    }

                    if(
                        (typeof mapDesigns['Front side'] == 'undefined' || !mapDesigns['Front side'])
                        && orderItem.printify_state.patternDesigns.length
                    ){
                        mapDesigns['Front side'] = orderItem.printify_state.patternDesigns[0].url;
                    }
                    
                    orderItem.printify_state.designs = mapDesigns;
                }

                if(profile.position) {
                    orderItem.printify_state.designPositions = profile.position;
                }

                safeApply();

                $scope.loadBlueprintPrintify(orderItem.printify_state.blueprint, orderItem);
            }

            const createPrintifyProduct = async (item) => 
            {
                const data = {
                    "title": "Product " + item.name,
                    "description": "Good product",
                    "blueprint_id": parseInt(item.printify_state.blueprint.blueprint_id),
                    "print_provider_id": parseInt(item.printify_state.printProvider.id),
                    "variants": [
                        {
                            "id": parseInt(item.printify_state.variant.id),
                            "is_enabled": true,
                            "price": parseFloat(item.price * 100),
                        }
                    ],
                    "print_areas": [{
                        "variant_ids": [item.printify_state.variant.id],
                        "placeholders": []
                    }]
                };

                // upload designs
                const uploadPromises = [];
                for (const key in item.printify_state.designs) {
                    if (Object.hasOwnProperty.call(item.printify_state.designs, key)) {
                        const url = item.printify_state.designs[key];
                        uploadPromises.push(uploadImageToPrintify(url, key));
                    }
                }

                const designAssets = await Promise.all(uploadPromises);
                const placeholders = [];

                // create placeholders
                for (let i = 0; i < designAssets.length; i++) {

                    const assetData = designAssets[i];
                    const placeholder = {
                        "position": assetData.key.toLowerCase().split(' ')[0],
                        "images": []
                    };

                    if(isAjustedPosition(item, assetData.key)) {
                        const positionData = item.printify_state.designPositions.position[assetData.key.toLowerCase().split(' ')[0]];
                        placeholder.images = [{
                            "id": assetData.value.data.id, 
                            "scale": positionData.scale,
                            "x": positionData.x,
                            "y": positionData.y,
                            "angle": positionData.angle
                        }];
                    } else {
                        placeholder.images = [{
                            "id": assetData.value.data.id,
                            "x": 0.5, 
                            "y": 0.5, 
                            "scale": 1,
                            "angle": 0
                        }];
                    }

                    placeholders.push(placeholder);

                }

                data.print_areas[0].placeholders = placeholders;

                // create product

                return new Promise((resolve) => {
                    sendCreatePrintifyProductRequest(data).then((response) => {
                        resolve(response)
                    });  
                });

            }

            const sendCreatePrintifyProductRequest = async (data) =>
            {
                const requestObj = $scope.buildLocaleData('/print-suppliers/printify/create-product', {
                    shop_id: $scope.printifyAccount.shop_id,
                    data
                }, $scope.fulFillLocale);

                return $scope.axiosClient.post(requestObj.url, requestObj.params);
            }

            const uploadImageToPrintify = (url, key) => 
            {
                function getFileFromUrl(url) {
                    const path = url.split('/');
                    return path[path.length - 1];
                }

                const params = new URLSearchParams({
                    end_point: '/v1/uploads/images.json',
                    base_api: 'https://api.printify.com',
                    shop_id: $scope.printifyAccount.shop_id,
                    method: "POST"
                }).toString();

                const requestObj = $scope.buildLocaleData('/print-suppliers/printify/api?' + params, {
                    "file_name": getFileFromUrl(url),
                    url
                }, $scope.fulFillLocale);

                return new Promise((resolve) => {
                    $scope.axiosClient.post(requestObj.url, {
                        params: requestObj.params
                    }).then((value) => {
                        resolve({
                            key, value
                        });
                    });
                });
            }
            $scope.is3Cols = function (options) {
                if (typeof options !== 'undefined' && options) {
                    return Object.keys(options).length;                
                }
            }

            $scope.initializePrintify();
        }
    };
});
