(function ($) {
    "use strict";

    if (typeof $ === 'undefined') {
        return;
    }

    var provincePlaceholder = window.selectProvinceLang || 'Select province';
    var cityPlaceholder = window.selectCityLang || 'Select city';
    var districtPlaceholder = window.selectDistrictLang || 'Select district';

    function getRegionForm($element) {
        var $form = $element.closest('form');
        return $form.length ? $form : $(document);
    }

    function enableSelect($select, enabled) {
        $select.prop('disabled', !enabled);

        if (enabled) {
            $select.removeAttr('disabled');
        }
    }

    function fillSelect($select, items, placeholder, disableWhenEmpty) {
        var html = '<option value="">' + placeholder + '</option>';

        if (items && items.length) {
            for (var i = 0; i < items.length; i++) {
                html += '<option value="' + items[i].id + '">' + items[i].title + '</option>';
            }
            enableSelect($select, true);
        } else {
            enableSelect($select, !disableWhenEmpty);
        }

        $select.html(html);
    }

    function toggleBillingFallbacks($form, showProvinceText, showCityText) {
        var $provinceText = $form.find('.js-billing-province-text');
        var $cityText = $form.find('.js-billing-city-text');
        var $citySelect = $form.find('select[name="city_id"]');
        var $billingCityInput = $form.find('input[name="billing_city"]');

        if ($provinceText.length) {
            $provinceText.toggleClass('d-none', !showProvinceText);
        }

        if ($cityText.length) {
            $cityText.toggleClass('d-none', !showCityText);

            if (showCityText) {
                enableSelect($citySelect, false);
                $citySelect.prop('required', false);
                $billingCityInput.prop('required', true);
            } else {
                $citySelect.prop('required', true);
                if ($citySelect.find('option').length > 1) {
                    enableSelect($citySelect, true);
                }
                $billingCityInput.prop('required', false);
            }
        }
    }

    function toggleDistrictFallback($form, showDistrictText) {
        var $districtText = $form.find('.js-billing-district-text');
        var $districtSelect = $form.find('select[name="district_id"]');

        if (!$districtText.length) {
            return;
        }

        $districtText.toggleClass('d-none', !showDistrictText);

        if (showDistrictText) {
            enableSelect($districtSelect, false);
        } else if ($districtSelect.find('option').length > 1) {
            enableSelect($districtSelect, true);
        }
    }

    function getRegionsBaseUrl() {
        var base = window.regionsApiBase || '/regions';
        return String(base).replace(/\/$/, '');
    }

    function regionUrl(path) {
        return getRegionsBaseUrl() + path;
    }

    function fetchRegions(url) {
        return $.ajax({
            url: url,
            method: 'GET',
            dataType: 'json'
        });
    }

    function loadProvinces(countryId) {
        return fetchRegions(regionUrl('/provincesByCountry/' + countryId)).then(function (result) {
            if (result && result.code === 200 && result.provinces) {
                return result.provinces;
            }
            return [];
        });
    }

    function loadCitiesByProvince(provinceId) {
        return fetchRegions(regionUrl('/citiesByProvince/' + provinceId)).then(function (result) {
            if (result && result.code === 200 && result.cities) {
                return result.cities;
            }
            return [];
        });
    }

    function loadCitiesByCountry(countryId) {
        return fetchRegions(regionUrl('/citiesByCountry/' + countryId)).then(function (result) {
            if (result && result.code === 200 && result.cities) {
                return result.cities;
            }
            return [];
        });
    }

    function loadDistricts(cityId) {
        return fetchRegions(regionUrl('/districtsByCity/' + cityId)).then(function (result) {
            if (result && result.code === 200 && result.districts) {
                return result.districts;
            }
            return [];
        });
    }

    function applyCities($form, cities) {
        var $citySelect = $form.find('select[name="city_id"]');
        fillSelect($citySelect, cities, cityPlaceholder, true);
        fillSelect($form.find('select[name="district_id"]'), [], districtPlaceholder, true);
        toggleDistrictFallback($form, true);

        if (!cities.length) {
            toggleBillingFallbacks($form, false, true);
        } else {
            toggleBillingFallbacks($form, false, false);
        }
    }

    function applyDistricts($form, districts) {
        var $districtSelect = $form.find('select[name="district_id"]');
        fillSelect($districtSelect, districts, districtPlaceholder, true);
        toggleDistrictFallback($form, !districts.length);
    }

    $('body').on('change', 'select[name="country_id"]', function () {
        var $this = $(this);
        var $form = getRegionForm($this);
        var countryId = $this.val();

        fillSelect($form.find('select[name="province_id"]'), [], provincePlaceholder, true);
        fillSelect($form.find('select[name="city_id"]'), [], cityPlaceholder, true);
        fillSelect($form.find('select[name="district_id"]'), [], districtPlaceholder, true);
        toggleBillingFallbacks($form, false, false);
        toggleDistrictFallback($form, true);

        if (!countryId) {
            return;
        }

        $this.prop('disabled', true);

        loadProvinces(countryId).done(function (provinces) {
            fillSelect($form.find('select[name="province_id"]'), provinces, provincePlaceholder, true);

            if (provinces.length) {
                toggleBillingFallbacks($form, false, false);
                return;
            }

            loadCitiesByCountry(countryId).done(function (cities) {
                applyCities($form, cities);

                if (!cities.length) {
                    toggleBillingFallbacks($form, true, true);
                }
            });
        }).fail(function () {
            toggleBillingFallbacks($form, true, true);
        }).always(function () {
            enableSelect($this, true);
        });
    });

    $('body').on('change', 'select[name="province_id"]', function () {
        var $this = $(this);
        var $form = getRegionForm($this);
        var provinceId = $this.val();

        fillSelect($form.find('select[name="city_id"]'), [], cityPlaceholder, true);
        fillSelect($form.find('select[name="district_id"]'), [], districtPlaceholder, true);
        toggleBillingFallbacks($form, false, false);
        toggleDistrictFallback($form, true);

        if (!provinceId) {
            return;
        }

        $this.prop('disabled', true);

        loadCitiesByProvince(provinceId).done(function (cities) {
            applyCities($form, cities);

            if (!cities.length) {
                toggleBillingFallbacks($form, false, true);
            }
        }).fail(function () {
            toggleBillingFallbacks($form, false, true);
        }).always(function () {
            enableSelect($this, true);
        });
    });

    $('body').on('change', 'select[name="city_id"]', function () {
        var $this = $(this);
        var $form = getRegionForm($this);
        var cityId = $this.val();

        fillSelect($form.find('select[name="district_id"]'), [], districtPlaceholder, true);
        toggleDistrictFallback($form, true);

        if (!cityId) {
            return;
        }

        $this.prop('disabled', true);

        loadDistricts(cityId).done(function (districts) {
            applyDistricts($form, districts);
        }).fail(function () {
            toggleDistrictFallback($form, true);
        }).always(function () {
            enableSelect($this, true);
        });
    });

    window.initRegionCascade = function ($form, selected) {
        if (!$form || !$form.length) {
            return;
        }

        selected = selected || {};

        var $country = $form.find('select[name="country_id"]');
        var countryId = $country.val();

        if (!countryId) {
            return;
        }

        var provinceId = selected.province_id || $form.find('select[name="province_id"]').val();
        var cityId = selected.city_id || $form.find('select[name="city_id"]').val();
        var districtId = selected.district_id || $form.find('select[name="district_id"]').val();

        loadProvinces(countryId).done(function (provinces) {
            var $provinceSelect = $form.find('select[name="province_id"]');
            fillSelect($provinceSelect, provinces, provincePlaceholder, true);

            if (provinceId) {
                $provinceSelect.val(String(provinceId));
            }

            if (provinces.length) {
                toggleBillingFallbacks($form, false, false);
            }

            var restoreDistricts = function (resolvedCityId) {
                if (!resolvedCityId) {
                    toggleDistrictFallback($form, true);
                    return;
                }

                loadDistricts(resolvedCityId).done(function (districts) {
                    var $districtSelect = $form.find('select[name="district_id"]');
                    fillSelect($districtSelect, districts, districtPlaceholder, true);
                    applyDistricts($form, districts);

                    if (districtId) {
                        $districtSelect.val(String(districtId));
                    }
                }).fail(function () {
                    toggleDistrictFallback($form, true);
                });
            };

            var restoreCities = function (cities) {
                applyCities($form, cities);

                if (cityId) {
                    $form.find('select[name="city_id"]').val(String(cityId));
                    restoreDistricts(cityId);
                } else if (!cities.length) {
                    toggleBillingFallbacks($form, !provinces.length, true);
                }
            };

            if (provinceId) {
                loadCitiesByProvince(provinceId).done(restoreCities);
            } else if (provinces.length) {
                toggleBillingFallbacks($form, false, false);
            } else {
                loadCitiesByCountry(countryId).done(restoreCities);

                if (!cityId) {
                    toggleBillingFallbacks($form, true, false);
                }
            }
        }).fail(function () {
            toggleBillingFallbacks($form, true, true);
            toggleDistrictFallback($form, true);
        });
    };

    window.refreshBillingRegions = function ($form, selected) {
        if (!$form || !$form.length) {
            return;
        }

        var $country = $form.find('select[name="country_id"]');

        if (!$country.val()) {
            return;
        }

        if (typeof window.initRegionCascade === 'function') {
            window.initRegionCascade($form, selected || {});
        }
    };
})(window.jQuery);
