import FreyaSyncService from './freya-sync-service';

import 'devbridge-autocomplete';
import $j from './lib/jquery';
import { ApiResponse } from './types/api-response';
import { AutocompleteResponse } from './types/autocomplete-response';
import { Suggestion } from './types/suggestion';

export default class AutocompleteClient {
    private sessionUid: string | undefined = undefined;
    private readonly serviceUrl: string;
    private lastResult?: Suggestion;

    constructor() {
        const data = FreyaSyncService.sharedInstance.data;
        if (!data.api_url.endsWith('/')) {
            data.api_url += '/';
        }
        this.serviceUrl = data.api_url;
    }

    private get placeDetailsUrl(): string {
        return `${this.serviceUrl}wp/getGooglePlaceDetails`;
    }

    public autocomplete(callbacks: {
        onSelect: (selected: Suggestion) => void;
        onSelectError?: (error: any) => void;
        onGoogleStartRequest?: () => void;
        onSearchStart?: () => void;
        onSearchComplete?: () => void;
        onSearchError?: () => void;
    }) {
        const settings = FreyaSyncService.sharedInstance.settings;

        // Nu stergeti asta, PHPStorm nu e de acord
        // @ts-ignore
        $j('#streetName').autocomplete({
            serviceUrl: (): string => {
                return `${this.serviceUrl}wp/geodecoding?sessionUid=${this.sessionUid ?? ''}`;
            },
            minChars: 3,
            paramName: 'q',
            params: {
                countyRestriction: settings.fsCountyRestriction,
                companyUid: settings.fsCompanyUid,
            },
            noCache: true,
            preventBadQueries: false, // Tine minte cautarile care nu au returnat nimic, si nu mai face call daca cauti a doua oara
            zIndex: 99999,
            showNoSuggestionNotice: true,
            noSuggestionNotice: 'Nu am gasit rezultate...',
            deferRequestBy: 300,
            transformResult: (response: string) => {
                const object = JSON.parse(response) as ApiResponse<AutocompleteResponse>;

                if (object.payload.session_uid) {
                    this.sessionUid = object.payload.session_uid;
                }

                return {
                    suggestions: $j.map(object.payload.suggestions, function (dataItem) {
                        return { value: dataItem.displayName, data: dataItem };
                    }),
                };
            },
            onSelect: (suggestion: AutocompleteSuggestion) => {
                const data = suggestion.data as Suggestion;
                if (data.type === 'google') {
                    if (this.lastResult && this.lastResult.id === data.id) {
                        callbacks.onSelect(this.lastResult);
                        return;
                    }
                    if (callbacks.onGoogleStartRequest) {
                        callbacks.onGoogleStartRequest();
                    }
                    try {
                        this.getGooglePlaceDetails(data.id).then((details) => {
                            this.lastResult = details;
                            callbacks.onSelect(details);
                        });
                        return;
                    } catch (e) {
                        if (callbacks.onSelectError) {
                            callbacks.onSelectError(e);
                        }
                        return;
                    }
                }

                if (data.type === 'nominatim') {
                    this.lastResult = data;
                    callbacks.onSelect(data);
                }
            },
            onSearchStart: function () {
                if (callbacks.onSearchStart) {
                    callbacks.onSearchStart();
                }
            },
            onSearchComplete: function () {
                if (callbacks.onSearchComplete) {
                    callbacks.onSearchComplete();
                }
            },
            onSearchError: function () {
                if (callbacks.onSearchError) {
                    callbacks.onSearchError();
                }
            },
        });
    }

    private async getGooglePlaceDetails(placeId: string): Promise<any> {
        if (!this.sessionUid) {
            throw new Error('Something went wrong');
        }
        const settings = FreyaSyncService.sharedInstance.settings;
        const data = {
            place_id: placeId,
            companyUid: settings.fsCompanyUid,
            sessionUid: this.sessionUid,
        };

        return new Promise(async (resolve, reject) => {
            const params = new URLSearchParams(data);
            const r = await fetch(`${this.placeDetailsUrl}?${params.toString()}`, {
                method: 'GET',
                headers: {
                    Accept: 'application/json',
                },
            });
            if (!r.ok) {
                if (r.headers.has('content-type') && r.headers.get('content-type') === 'application/json') {
                    const response = (await r.json()) as ApiResponse<any>;
                    reject(response);
                }
            }

            const response = (await r.json()) as ApiResponse<any>;
            this.sessionUid = undefined;
            resolve(response.payload);
        });
    }
}
