import Autocomplete from "https://cdn.jsdelivr.net/gh/lekoala/bootstrap5-autocomplete@master/autocomplete.js";

class Addresses {

    constructor(cityInputId, provinceInputId, countryInputId, zipInputId) {
        this.cityInputId = cityInputId;
        this.provinceInputId = provinceInputId;
        this.countryInputId = countryInputId;
        this.zipInputId = zipInputId;

        this.setupCityAutocomplete();

        this.handleCountryChange = this.handleCountryChange.bind(this);
        this.handleProvinceChange = this.handleProvinceChange.bind(this);
        this.handleCityBlur = this.handleCityBlur.bind(this);
        this.handleZipBlur = this.handleZipBlur.bind(this);
        this.handleCityKeyup = this.handleCityKeyup.bind(this);

        const countryInput = document.getElementById(this.countryInputId);
        if (countryInput) {
            countryInput.addEventListener('change', this.handleCountryChange);

            this.allCountries = [];

            if ($('#' + this.countryInputId)[0].options.length > 1) {
                for (var i = 0; i < $('#' + this.countryInputId)[0].options.length; i++) {
                    this.allCountries.push($('#' + this.countryInputId)[0].options[i]);
                }
            }
            else {
                this.initCountries();
            }
        }

        const provinceInput = document.getElementById(this.provinceInputId);
        if (provinceInput) {
            provinceInput.addEventListener('change', this.handleProvinceChange);

            this.allProvinces = [];

            if ($('#' + this.provinceInputId)[0].options.length > 1) {
                for (var i = 0; i < $('#' + this.provinceInputId)[0].options.length; i++) {
                    this.allProvinces.push($('#' + this.provinceInputId)[0].options[i]);
                }
            }
            else {
                this.initProvinces();
            }
        }

        const cityInput = document.getElementById(this.cityInputId);
        if (cityInput) {
            cityInput.addEventListener('keyup', this.handleCityKeyup);

            this.timeout = null;
            $('#' + this.cityInputId).keyup((event) => {
                clearTimeout(this.timeout);
                this.timeout = setTimeout(() => {
                    this.setCities(event);
                }, 500);
            });

            cityInput.addEventListener('blur', this.handleCityBlur);
        }

        const zipInput = document.getElementById(this.zipInputId);
        if (zipInput) {
            zipInput.addEventListener('blur', this.handleZipBlur);
        }
    }

    setupCityAutocomplete() {
        var src = [];
        const cityInput = document.getElementById(this.cityInputId);
        if (cityInput) {
            Autocomplete.init("input.autocomplete", {
                items: src,
                valueField: "id",
                labelField: "title",
                highlightTyped: false
            });
        }
    }

    fillCities() {
        const src = [];

        for (const key in this.cities) {
            if (!src.find(e => e.title === this.cities[key].City)) {
                src.push({
                    title: this.cities[key].City,
                    id: key,
                    data: {
                        key: key,
                    },
                });
            }
        }

        const cityInput = document.getElementById(this.cityInputId);
        const inst = Autocomplete.getInstance(cityInput);
        inst.setData(src);
        inst.showOrSearch();
    }

    fillStates(citiesArray, statesDropDown, city, country) {
        var stateSelected = undefined;
        var stateSelectedIndex = 0;
        if (statesDropDown.selectedIndex > 0) {
            stateSelected = statesDropDown.options[statesDropDown.selectedIndex].text
        }

        this.removeOptions(statesDropDown);
        var states = [{ text: 'Select', value: 'Select' }];

        // filter the provinces by city
        if (city != undefined) {
            for (var key in citiesArray) {
                if (!states.includes(citiesArray[key].Province)) {
                    if (city != undefined && city == citiesArray[key].City) {
                        states.push({ text: citiesArray[key].Province, value: citiesArray[key].Province });
                    }
                }
            }

            this.buildProvinceDropDown(states, stateSelected, statesDropDown, stateSelectedIndex);
        }
        // filter the provinces by country
        else if (country != undefined) {
            parent.openModalSpinner();
            var filter = JSON.stringify({ "country": country });
            $.ajax({
                type: "POST",
                url: "/PatientAccess/Services/CityService.asmx/GetProvinces",
                data: filter,
                contentType: "application/json;charset=utf-8",
                dataType: "json",

                success: (provincesJson) => {
                    if (provincesJson.d) {
                        var jsonResult = JSON.parse(provincesJson.d);
                        if (jsonResult.provincesListValues.length > 0) {
                            for (var key in jsonResult.provincesListValues) {
                                states.push({ text: jsonResult.provincesListValues[key].Province, value: jsonResult.provincesListValues[key].Province });
                            }

                            this.buildProvinceDropDown(states, stateSelected, statesDropDown, stateSelectedIndex);
                        }
                    }
                    parent.closeModalSpinner();
                },
                error: function (err) {
                    console.log(err);
                    parent.closeModalSpinner();
                }
            });
        }
        else {
            if (states.length == 1) {
                states = [];
                for (var key in this.allProvinces) {
                    states.push({ text: this.allProvinces[key].text, value: this.allProvinces[key].value });
                }
            }

            this.buildProvinceDropDown(states, stateSelected, statesDropDown, stateSelectedIndex);
        }
    }

    fillCountries(city, state) {

        let countriesDropDown = document.getElementById(this.countryInputId);
        var countrySelected = undefined;
        var countrySelectedIndex = 0;
        if (countriesDropDown.selectedIndex > 0) {
            countrySelected = countriesDropDown.options[countriesDropDown.selectedIndex].text
        }

        this.removeOptions(countriesDropDown);
        var countries = [{ text: 'Select', value: 'Select' }];

        // filter the country by city
        if (city != undefined) {
            for (var key in this.cities) {
                if (!countries.find(e => e.text === this.cities[key].Country)) {
                    if (city == undefined || (city != undefined && city == this.cities[key].City)) {
                        countries.push({ text: this.cities[key].Country, value: this.cities[key].Country });
                    }
                }
            }

            this.buildCountryDropDown(countries, countrySelected, countriesDropDown, countrySelectedIndex);
        }
        // filter the country by province
        else if (state != undefined) {
            parent.openModalSpinner();
            var filter = JSON.stringify({ "province": state });
            $.ajax({
                type: "POST",
                url: "/PatientAccess/Services/CityService.asmx/GetCountries",
                data: filter,
                contentType: "application/json;charset=utf-8",
                dataType: "json",
                success: (countriesJson) => {
                    if (countriesJson.d) {
                        var jsonResult = JSON.parse(countriesJson.d);
                        if (jsonResult.countryListValues.length > 0) {
                            for (var key in jsonResult.countryListValues) {
                                countries.push({ text: jsonResult.countryListValues[key].Country, value: jsonResult.countryListValues[key].Country });
                            }

                            this.buildCountryDropDown(countries, countrySelected, countriesDropDown, countrySelectedIndex);
                        }
                    }
                    parent.closeModalSpinner();
                },
                error: function (err) {
                    console.log(err);
                    parent.closeModalSpinner();
                }
            });
        }
        else {
            // reset when nothing is found
            if (countries.length == 1) {
                countries = [];
                for (var key in this.allCountries) {
                    countries.push({ text: this.allCountries[key].text, value: this.allCountries[key].text });
                }
            }

            this.buildCountryDropDown(countries, countrySelected, countriesDropDown, countrySelectedIndex);
        }
    }

    handleCityKeyup(event) {
        if (this.canSearchCity(event)) {
            this.showInputSpinner();
        }
        else {
            this.hideInputSpinner();
        }
    }

    handleCountryChange() {
        const countries = document.getElementById(this.countryInputId);
        const provinceInput = document.getElementById(this.provinceInputId);

        if (countries.selectedIndex == 0) {
            this.fillStates(this.cities, provinceInput, undefined, undefined);
            this.fillCountries();
        } else {
            const selectedCountry = countries.options[countries.selectedIndex].text;
            this.fillStates(this.cities, provinceInput, undefined, selectedCountry);
        }
    }

    handleProvinceChange() {
        var states = document.getElementById(this.provinceInputId);
        var zip = document.getElementById(this.zipInputId);

        if (states.selectedIndex == 0) {
            this.fillStates(this.cities, states, undefined, undefined);
            this.fillCountries();
        }
        else {
            this.fillCountries(undefined, states.options[states.selectedIndex].value);
            this.handleZipBlur();
        }
    }

    handleZipBlur() {

        if ($('#' + this.zipInputId).val() != "") {
            parent.openModalSpinner();
            var filter = JSON.stringify({ "postal": $('#' + this.zipInputId).val() });
            $.ajax({
                type: "POST",
                url: "/PatientAccess/Services/CityService.asmx/GetCityInfo",
                data: filter,
                contentType: "application/json;charset=utf-8",
                dataType: "json",
                success: (citiesJson) => {
                    if (citiesJson.d) {
                        var jsonResult = JSON.parse(citiesJson.d);
                        if (jsonResult.cityListValues.length > 0) {
                            var userCity = $('#' + this.cityInputId).val();
                            var userProvince = $("#" + this.provinceInputId + " option:selected").val();
                            var found = false;

                            for (var key in jsonResult.cityListValues) {
                                if ((userCity == "" || jsonResult.cityListValues[key].City == userCity) &&
                                    (userProvince == "Select" || jsonResult.cityListValues[key].Province == userProvince)) {

                                    found = true;
                                    break;
                                }
                            }

                            if (found) {
                                $('#' + this.zipInputId).removeClass('is-invalid');
                            }
                            else {
                                $('#' + this.zipInputId).addClass('is-invalid');
                            }
                        }
                        else {
                            $('#' + this.zipInputId).addClass('is-invalid');
                        }
                    }
                    parent.closeModalSpinner();
                },
                error: function (err) {
                    console.log(err);
                    parent.closeModalSpinner();
                }
            });
        }
        else {
            $('#' + this.zipInputId).addClass('is-invalid');
        }
    }

    handleCityBlur() {

        let statesDropDown = document.getElementById(this.provinceInputId);

        if ($('#' + this.cityInputId).val() != "") {

            var cityDetails = this.getCityDetails(this.cities);

            if (cityDetails == undefined) {

                // search cities in case user types fast and move focus to another field
                var filter = this.getSearchCitiesFilter();
                parent.openModalSpinner();

                $.ajax({
                    type: "POST",
                    url: "/PatientAccess/Services/CityService.asmx/GetCities",
                    data: filter,
                    contentType: "application/json;charset=utf-8",
                    dataType: "json",
                    success: (cities) => {

                        if (cities.d) {
                            var jsonResult = JSON.parse(cities.d);
                            if (jsonResult.cityListValues.length > 0) {

                                this.cities = jsonResult.cityListValues;
                                this.fillCities();

                                var cityDetails = this.getCityDetails(this.cities);

                                if (cityDetails == undefined) {
                                    this.markCityAsInvalid();
                                    this.fillStates(this.cities, statesDropDown, $('#' + this.cityInputId).val(), undefined);
                                    if (this.countryInputId != undefined) {
                                        this.fillCountries($('#' + this.cityInputId).val(), undefined);
                                    }
                                }
                                else {
                                    this.setProvinceAndCountryByCity(statesDropDown, cityDetails);
                                    if ($('#' + this.zipInputId).val() != "") {
                                        this.handleZipBlur();
                                    }
                                }
                            }
                            else { // no city has been found
                                this.markCityAsInvalid();
                                this.fillStates(this.cities, statesDropDown, $('#' + this.cityInputId).val(), undefined);
                                if (this.countryInputId != undefined) {
                                    this.fillCountries($('#' + this.cityInputId).val(), undefined);
                                }
                            }
                        }

                        this.hideInputSpinner();
                        parent.closeModalSpinner();
                    },
                    error: function () {
                        this.markCityAsInvalid();
                        parent.closeModalSpinner();
                    }
                });
            }
            else {
                this.setProvinceAndCountryByCity(statesDropDown, cityDetails);
                if ($('#' + this.zipInputId).val() != "") {
                    this.handleZipBlur();
                }
            }
        }
        else { // reset state and country fields
            this.markCityAsInvalid();
            this.fillStates(this.cities, statesDropDown, undefined, undefined);
            if (this.countryInputId != undefined) {
                this.fillCountries();
            }
        }
    }

    buildCountryDropDown(countries, countrySelected, countriesDropDown, countrySelectedIndex) {
        countries.map((country, i) => {
            let opt = document.createElement("option");
            opt.value = country.value; // the index
            opt.innerHTML = country.text;
            countriesDropDown.append(opt);

            if (countrySelected != undefined && countrySelected == country.text) {
                countrySelectedIndex = i;
            }
        });

        if (countries.length == 2) {
            $('#' + this.countryInputId).removeClass("is-invalid");
            countriesDropDown.selectedIndex = 1;
        }
        else if (countrySelected != undefined) {
            countriesDropDown.selectedIndex = countrySelectedIndex;
        }
    }

    buildProvinceDropDown(states, stateSelected, statesDropDown, stateSelectedIndex) {
        states.map((state, i) => {
            let opt = document.createElement("option");
            opt.value = state.value; // the index
            opt.innerHTML = state.text;
            statesDropDown.append(opt);

            if (stateSelected != undefined && stateSelected == state.text) {
                stateSelectedIndex = i;
            }
        });

        if (states.length == 2) {
            $('#' + this.provinceInputId).removeClass("is-invalid");
            statesDropDown.selectedIndex = 1;
        }
        else if (stateSelected != undefined) {
            statesDropDown.selectedIndex = stateSelectedIndex;
        }
    }

    hideInputSpinner() {
        var iconContainer = $('#' + this.cityInputId).closest('.inputspinner').find('.icon-inputspinner');
        iconContainer.css('display', 'none');
    }

    showInputSpinner() {
        var pos = $('#' + this.cityInputId).position();
        var width = $('#' + this.cityInputId).outerWidth();

        var iconContainer = $('#' + this.cityInputId).closest('.inputspinner').find('.icon-inputspinner');
        iconContainer.css({
            top: (pos.top + 10) + "px",
            left: ((pos.left - 30) + width) + "px",
            display: "block"
        });
    }

    updateInputSpinnerPosition(isInvalid) {
        var iconContainer = $('#' + this.cityInputId).closest('.inputspinner').find('.icon-inputspinner');
        if (isInvalid) {
            iconContainer.addClass('icon-inputspinner-invalid-input');
        }
        else {
            iconContainer.removeClass('icon-inputspinner-invalid-input');
        }
    }

    removeOptions(selectElement) {
        var i, L = selectElement.options.length - 1;
        for (i = L; i >= 0; i--) {
            selectElement.remove(i);
        }
    }

    markCityAsInvalid() {
        $('#' + this.cityInputId).addClass('is-invalid');
        this.updateInputSpinnerPosition(true);
    }

    canSearchCity(event) {
        var allowedkey = (event.which >= 48 && event.which <= 90) || event.which == 32 || event.which == 8 || event.which == 46; // allowed only alphanumeric, space, backspace, delete

        return allowedkey && $('#' + this.cityInputId).val().length >= 3;
    }

    getCityDetails(citiesArray) {
        var city = undefined;
        for (var key in citiesArray) {

            if (citiesArray[key].City.toUpperCase() == $('#' + this.cityInputId).val().toUpperCase()) {
                city = citiesArray[key];
                $('#' + this.cityInputId).val(city.City);
                break;
            }
        }

        return city;
    }

    getSearchCitiesFilter() {
        var selectedStateIndex = $('#' + this.provinceInputId).prop('selectedIndex');
        var selectedState = selectedStateIndex == 0 ? '' : $("#" + this.provinceInputId + " option").eq(selectedStateIndex).val();

        var selectedCountryIndex = $("#" + this.countryInputId).prop('selectedIndex');
        var selectedCountry = selectedCountryIndex == 0 ? '' : $("#" + this.countryInputId + " option").eq(selectedCountryIndex).text();
        var filter = JSON.stringify({ "city": $('#' + this.cityInputId).val(), "province": selectedState, "country": selectedCountry });

        return filter;
    }

    setProvinceAndCountryByCity(statesDropDown, cityDetails) {
        if (statesDropDown.selectedIndex > 0 && statesDropDown.options[statesDropDown.selectedIndex].value != cityDetails.Province) {
            this.markCityAsInvalid();
            return;
        }

        if (this.countryInputId != undefined) {
            let countriesDropDown = document.getElementById(this.countryInputId);
            if (countriesDropDown.selectedIndex > 0 && countriesDropDown.options[countriesDropDown.selectedIndex].text != cityDetails.Country) {
                this.markCityAsInvalid();
                return;
            }
        }

        this.updateInputSpinnerPosition(false);

        this.fillStates(this.cities, statesDropDown, $('#' + this.cityInputId).val(), undefined);
        if (this.countryInputId != undefined) {
            this.fillCountries($('#' + this.cityInputId).val(), undefined);
        }
    }

    setCities(event) {
        if (this.canSearchCity(event)) {
            var filter = this.getSearchCitiesFilter();
            this.showInputSpinner();

            $.ajax({
                type: "POST",
                url: "/PatientAccess/Services/CityService.asmx/GetCities",
                data: filter,
                contentType: "application/json;charset=utf-8",
                dataType: "json",
                success: (cities) => {
                    if (cities.d) {
                        var jsonResult = JSON.parse(cities.d);
                        if (jsonResult.cityListValues.length > 0) {
                            this.cities = jsonResult.cityListValues;
                            this.fillCities();
                        }
                    }
                    this.hideInputSpinner();
                },
                error: function (err) {
                    console.log(err);
                    this.hideInputSpinner();
                }
            });
        }
        else if ($('#' + this.cityInputId).val().length < 3) {
            this.cities = [];
            this.fillCities(); // clean
        }
    }

    initCountries() {
        let countriesDropDown = document.getElementById(this.countryInputId);
        this.removeOptions(countriesDropDown);
        var countries = [{ text: 'Select', value: 'Select' }];
        var filter = JSON.stringify({ "province": "" });

        $.ajax({
            type: "POST",
            url: "/PatientAccess/Services/CityService.asmx/GetCountries",
            data: filter,
            contentType: "application/json;charset=utf-8",
            dataType: "json",
            success: (countriesJson) => {
                if (countriesJson.d) {
                    var jsonResult = JSON.parse(countriesJson.d);
                    if (jsonResult.countryListValues.length > 0) {
                        for (var key in jsonResult.countryListValues) {
                            countries.push({ text: jsonResult.countryListValues[key].Country, value: jsonResult.countryListValues[key].Country });
                        }

                        this.buildCountryDropDown(countries, undefined, countriesDropDown, undefined);
                        for (var i = 0; i < $('#' + this.countryInputId)[0].options.length; i++) {
                            this.allCountries.push($('#' + this.countryInputId)[0].options[i]);
                        }
                    }
                }
            },
            error: function (err) {
                console.log(err);
            }
        });
    }

    initProvinces() {
        let provincesDropDown = document.getElementById(this.provinceInputId);
        this.removeOptions(provincesDropDown);
        var provinces = [{ text: 'Select', value: 'Select' }];

        $.ajax({
            type: "POST",
            url: "/PatientAccess/Services/CityService.asmx/GetAllProvinces",
            data: "{}",
            contentType: "application/json;charset=utf-8",
            dataType: "json",

            success: (provincesJson) => {
                if (provincesJson.d) {
                    var jsonResult = JSON.parse(provincesJson.d);
                    if (jsonResult.provincesListValues.length > 0) {
                        for (var key in jsonResult.provincesListValues) {
                            provinces.push({ text: jsonResult.provincesListValues[key].Province, value: jsonResult.provincesListValues[key].Province });
                        }

                        this.buildProvinceDropDown(provinces, undefined, provincesDropDown, undefined);
                        for (var i = 0; i < $('#' + this.provinceInputId)[0].options.length; i++) {
                            this.allProvinces.push($('#' + this.provinceInputId)[0].options[i]);
                        }
                    }
                }
            },
            error: function (err) {
                console.log(err);
            }
        });
    }
}

export default Addresses;