import 'devbridge-autocomplete';
import AutocompleteClient from './autocomplete-client';
import FreyaSyncService from './freya-sync-service';
import { ApiResponse } from './types/api-response';
import { Suggestion } from './types/suggestion';
import $j from './lib/jquery';
import { SetLocationForm } from './types/set-location-form';

type GetLocationDataForm = {
    streetName?: string;
    streetNo?: string;
    blockNo?: string;
    apartmentNo?: string;
    pickup: boolean;
    chosenLocationUid?: string;
    geo?: any;
    uid?: string;
};

export default class ModalAddress {
    private static instance: ModalAddress;
    private suggestion: any | undefined = undefined;
    private autocompleteClient: AutocompleteClient;

    private constructor() {
        this.autocompleteClient = new AutocompleteClient();

        this.setupJquery();
    }

    public static bootstrap() {
        if (this.instance) {
            return;
        }

        this.instance = new ModalAddress();
    }

    public static get sharedInstance(): ModalAddress {
        if (!this.instance) {
            throw new Error('No ModalAddress instance');
        }

        return this.instance;
    }

    private blockInterface() {
        $j('.fsUserAddressForm > input').attr('readonly', 'true');
        $j('.modal__buttons > button').prop('disabled', true);
        $j('.cancelLoading').css('display', 'inline-block');
        $j('.address-modal-save').prop('disabled', true);
        $j('.address-modal-close').prop('disabled', true);
        $j('.address-modal-save > i').css('display', 'inline-block');
        $j('.streetNoLoading').css('display', 'inline-block');
    }

    private unBlockInterface() {
        $j('.fsUserAddressForm > input').attr('readonly', 'false');
        $j('.modal__buttons > button').prop('disabled', false);
        $j('.cancelLoading').css('display', 'none');
        $j('.address-modal-save').prop('disabled', false);
        $j('.address-modal-close').prop('disabled', false);
        $j('.address-modal-save > i').css('display', 'none');
        $j('.streetNoLoading').css('display', 'hide');
    }

    private onModalDismissed() {
        const cancelLoading = $j('.cancelLoading');
        const modal = $j('#modal');
        const data = FreyaSyncService.sharedInstance.data;
        cancelLoading.css('display', 'inline-block');
        this.blockInterface();
        $j.ajax({
            type: 'POST',
            url: data.ajax_url,
            dataType: 'json',
            data: { action: 'cart_service_service_modal_dismissed' },
            success: () => {
                cancelLoading.css('display', 'none');
                modal.removeClass('modal-visible');
                this.unBlockInterface();
            },
            error: (xhr, ajaxOptions, thrownError) => {
                cancelLoading.css('display', 'none');
                alert(xhr.status);
                alert(thrownError);
            },
        });
    }

    private hasPickup(): boolean {
        if (!$j("input[type='radio'][name='deliveryType']").length) {
            // No radio button exists
            return $j('select#location').length !== 0;
        }

        return $j("input[type='radio'][name='deliveryType']:checked").val() === '2';
    }

    private validateModal(): boolean {
        const errorMessages = $j('#localizationModalErrorMessages');
        const successMessages = $j('#localizationModalSuccessMessages');
        const streetNo = $j('#streetNo');
        const loadingElem = $j('.mLoading');
        const pickup = this.hasPickup();
        if (pickup) {
            return true;
        }

        if (!this.suggestion || typeof this.suggestion !== 'object') {
            loadingElem.css('display', 'none');
            errorMessages.show();
            successMessages.hide();
            errorMessages.html('Vă rugăm să introduceți strada și numărul, apoi selectați o adresă din listă.');
            this.unBlockInterface();
            return false;
        }

        if (!streetNo.val() || streetNo.val() === '') {
            loadingElem.css('display', 'none');
            errorMessages.show();
            successMessages.hide();
            errorMessages.html('Vă rugăm să introduceți numarul străzii.');
            this.unBlockInterface();
            return false;
        }
        return true;
    }

    private async onModalSave() {
        this.blockInterface();
        const errorMessages = $j('#localizationModalErrorMessages');
        const successMessages = $j('#localizationModalSuccessMessages');
        const streetNo = $j('#streetNo');
        const loadingElem = $j('.mLoading');

        if (!this.validateModal()) {
            return;
        }
        errorMessages.hide();

        const pickup = this.hasPickup();

        const locationData = await this.getLocationData(pickup);
        if (!locationData || !locationData.status) {
            const message = locationData?.message ?? 'Ceva nu a mers bine, vă rugăm să încercați din nou.';
            loadingElem.css('display', 'none');
            errorMessages.show().text(message);
            successMessages.hide();
            this.unBlockInterface();
            return;
        }

        if (pickup) {
            const select = $j('#modal select#location');
            let uid: string | undefined = undefined;
            if (select) {
                uid = String(select.find(':selected').val() ?? '');
            }
            const data: SetLocationForm = {
                pickup: true,
            };
            if (uid) {
                data.locationUid = uid;
            }

            successMessages
                .show()
                .text(
                    `Locația care vă procesează comanda este: ${locationData.payload.name}. Vă rugăm să așteptați câteva momente.`
                );
            errorMessages.hide();

            this.setLocation(data, locationData.payload.url);
            return;
        }

        successMessages
            .show()
            .text(
                `Locația care vă procesează comanda este: ${locationData.payload.name}. Vă rugăm să așteptați câteva momente.`
            );
        errorMessages.hide();

        const data: SetLocationForm = {
            geo: this.suggestion,
            taxes: locationData.payload.taxes,
            locationUid: locationData.payload.locationUid,
            companyUid: FreyaSyncService.sharedInstance.settings.fsCompanyUid,
            streetNo: String(streetNo.val()),
            blockNo: String($j('.fsUserAddressForm > #blockNo').val() ?? ''),
            floor: String($j('.fsUserAddressForm > #blockNo').val() ?? ''),
            entranceNo: String($j('.fsUserAddressForm > #blockNo').val() ?? ''),
            apartmentNo: String($j('.fsUserAddressForm > #blockNo').val() ?? ''),
        };
        this.setLocation(data, locationData.payload.url);
    }

    private async getLocationData(pickup: boolean = false) {
        let formData: GetLocationDataForm = {
            pickup,
            uid: FreyaSyncService.sharedInstance.settings.fsCompanyUid,
        };
        if (pickup) {
            const select = $j('#modal select#location');
            let uid: string | undefined;
            if (select) {
                uid = String(select.find(':selected').val() ?? '');
            } else {
                uid = FreyaSyncService.sharedInstance.settings.fsDefaultLocationUid;
            }
            formData.chosenLocationUid = uid;
        } else {
            formData.streetName = String($j('#streetName').val() ?? '');
            formData.streetNo = String($j('#streetNo').val() ?? '');
            formData.blockNo = String($j('#blockNo').val() ?? '');
            formData.apartmentNo = String($j('#apartmentNo').val() ?? '');
            formData.geo = this.suggestion;
        }
        try {
            const r = await fetch(this.findCloserLocationUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(formData),
            });
            if (!r.ok) {
                if (r.headers.get('content-type') === 'application/json') {
                    return (await r.json()) as ApiResponse<any>;
                }
                return undefined;
            }
            return (await r.json()) as ApiResponse<any>;
        } catch (e) {
            return undefined;
        }
    }

    private setLocation(data: SetLocationForm, url: string | undefined) {
        if (!FreyaSyncService.sharedInstance.settings.fsEnableMultiSubdomain) {
            this.setLocationSingleSite(data);
            return;
        }

        const errorMessages = $j('#localizationModalErrorMessages');
        const successMessages = $j('#localizationModalSuccessMessages');

        const encoded = btoa(encodeURIComponent(JSON.stringify(data)));
        if (!url) {
            successMessages.hide();
            errorMessages.show().text('Nu am putut redirecționa browser-ul către locația aleasă. Încercați din nou.');
            this.unBlockInterface();
            return;
        }
        location.href = `${url}?redirect-payload=${encoded}`;
    }

    private setLocationSingleSite(data: SetLocationForm) {
        this.blockInterface();
        $j.ajax({
            type: 'POST',
            url: FreyaSyncService.sharedInstance.data.ajax_url,
            data: {
                action: 'fss_set_location_settings',
                nonce: FreyaSyncService.sharedInstance.data.nonce,
                ...data,
            },
            dataType: 'json',
            success: (response) => {
                if (!response.success) {
                    let message = 'Ceva nu a mers bine, vă rugăm să încercați din nou.';
                    $j('#localizationModalErrorMessages').show().text(message);
                    this.unBlockInterface();
                    return;
                }
                $j('.mLoading').hide();
                this.unBlockInterface();
                $j('#modal').removeClass('modal-visible');
                location.reload();
            },
            error: (xhr: JQuery.jqXHR<ApiResponse<any>>) => {
                let message = 'Ceva nu a mers bine, vă rugăm să încercați din nou.';
                if (xhr.responseJSON.message) {
                    message = xhr.responseJSON.message;
                }
                $j('#localizationModalErrorMessages').show().text(message);
                this.unBlockInterface();
            },
        });
    }

    private openModal() {
        $j('#modal').addClass('modal-visible');
        if ($j('.xoo-wsch-close')[0]) {
            $j('.xoo-wsch-close').trigger('click');
        }
    }

    private setupStreetAutocomplete() {
        this.autocompleteClient.autocomplete({
            onSelect: (suggestion: Suggestion) => {
                this.unBlockInterface();
                $j('#streetNo').val('');
                if (suggestion.streetNumber) {
                    if (suggestion.streetNumber) {
                        $j('#streetNo').val(suggestion.streetNumber);
                    }
                }
                this.suggestion = suggestion;
            },
            onSelectError: (error: any) => {
                this.unBlockInterface();
                $j('.cancelLoading').css('display', 'none');
                $j('.streetNoLoading').css('display', 'none');
                $j('#localizationModalErrorMessages')
                    .show()
                    .text(error.message ?? 'Ceva nu a mers bine!');
            },
            onGoogleStartRequest: () => {
                this.blockInterface();
            },
            onSearchStart: () => {
                $j('.streetNameLoading').css('display', 'inline');
            },
            onSearchComplete: () => {
                $j('.streetNameLoading').css('display', 'none');
            },
            onSearchError: () => {
                $j('.streetNameLoading').css('display', 'none');
            },
        });
    }

    private setupJquery() {
        const deliveryForm = $j('#modal .modal__fields_group');
        const loading = $j('.mLoading');
        const cancelLoading = $j('.cancelLoading');
        const locationSelect = $j('#modal .location-select-container');
        loading.css('display', 'none');
        loading.css('display', 'none');
        cancelLoading.css('display', 'none');
        const checked = $j("input[type='radio'][name='deliveryType']:checked").val();
        switch (checked) {
            case '1':
                deliveryForm.removeClass('fss-hide');
                locationSelect.addClass('fss-hide');
                break;
            case '2':
                deliveryForm.addClass('fss-hide');
                locationSelect.removeClass('fss-hide');
                break;
        }

        $j("input[type='radio'][name='deliveryType']").on('change', () => {
            const value = $j("input[type='radio'][name='deliveryType']:checked").val();
            switch (value) {
                case '1':
                    deliveryForm.removeClass('fss-hide');
                    locationSelect.addClass('fss-hide');
                    break;
                case '2':
                    deliveryForm.addClass('fss-hide');
                    locationSelect.removeClass('fss-hide');
                    break;
            }
        });

        $j('.address-modal-close').on('click', () => {
            this.onModalDismissed();
        });
        $j('.address-modal-save').on('click', async () => {
            await this.onModalSave();
        });
        $j('.address-modal-open').on('click', () => {
            this.openModal();
        });
        this.setupStreetAutocomplete();
    }

    get findCloserLocationUrl(): string {
        const data = FreyaSyncService.sharedInstance.data;
        return data.api_url + 'wp/findCloserLocation';
    }
}
