import { AppRequest } from './models';
import { IApp } from './interfaces';
declare global {
    interface Window {
        App: IApp;
        Sentry: any;
        select: any;
    }
}


function getMeta(name) {
    const meta = document.querySelector('meta[name="' + name + '"]');

    if (meta) {
        return meta.getAttribute('content');
    } else {
        return '#FFFFFFFF';
    }
}

const isAndroid = /android/i.test(navigator.userAgent);
if (typeof window.App !== 'undefined') {
    if (!window.App.on) {
        const appDebug = localStorage && localStorage.getItem('appDebug') === 'true';
        let requestId = 0;
        const handlers: ((...args) => boolean | void)[][] = [];
        const requests: AppRequest[] = [];
        window.App = new Proxy(window.App, {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            get(target: any, propKey: string) {
                if (propKey === 'isWeb') {
                    return false;
                }
                return (...args) => {
                    if (window.Sentry && appDebug) {
                        window.Sentry.captureMessage(propKey, {
                            extra: args,
                            level: 'info',
                        });
                    }
                    if (propKey === 'emit') {
                        const channel = args.shift();
                        if (channel in handlers) {
                            try {
                                let success = true;
                                for (const handler of handlers[channel]) {
                                    success = success && handler(...args) !== false;
                                }
                                return success;
                            } catch (e) {
                                return false;
                            }
                        } else {
                            return false;
                        }
                    } else if (propKey === 'onSuccess' || propKey === 'onError' || propKey === 'resolve' || propKey === 'reject') {
                        const request = requests[args[0]];
                        if (request) {
                            if (args.length > 1) {
                                return request[propKey](args[1]);
                            } else {
                                return request[propKey]();
                            }
                        } else {
                            // eslint-disable-next-line max-len, no-console
                            console.error('Unable to resolve request. (id=' + args[0] + ', now=' + Date.now() + ', data=' + JSON.stringify(args[1]) + ')');
                        }
                    } else if (target[propKey] === undefined) {
                        if (propKey === 'on') {
                            if (!handlers[args[0]]) {
                                handlers[args[0]] = [];
                            }
                            handlers[args[0]].push(args[1]);
                        }
                        const id = 'req-' + (requestId++) + '-' + Date.now();
                        if (isAndroid) {
                            if (target.request) {
                                return new Promise((resolve, reject) => {
                                    requests[id] = { resolve, reject };
                                    target.request(propKey, id, JSON.stringify(args));
                                });
                            } else {
                                return new Promise((resolve, reject) => {
                                    requests[id] = { resolve, reject };
                                    target.postMessage(propKey, id, JSON.stringify(args));
                                });
                            }
                        } else {
                            return target.postMessage(JSON.stringify({ method: propKey, params: args })).then((result) => {
                                if (result && result.compatError) {
                                    throw result.compatError;
                                } else {
                                    return result;
                                }
                            });
                        }
                    }
                };
            },
        });


        // Bypass native browser functionalities
        if (isAndroid) {
            window.print = () => window.App.print();
            navigator.share = (data) => window.App.share(data);
            navigator.clipboard.writeText = (data) => window.App.copy(data);
            navigator.clipboard.readText = () => window.App.paste();
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            navigator.setAppBadge = (data) => window.App.setAppBadge(data);
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            navigator.clearAppBadge = () => window.App.clearAppBadge();
            navigator.vibrate = (data) => window.App.vibrate(data);
            window.open = (url, name) => window.App.openUrl(url, name);

            if (!('permissions' in navigator)) {
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                navigator.permissions = {};
            }
            navigator.permissions.query = window.App.hasPermission;
        } else {
            const positionCallbacks: any[] = [];
            window.print = () => window.App.print();
            window.open = (url, name) => window.App.openUrl(url, name);
            navigator.share = (data) => window.App.share(data);
            navigator.clipboard.writeText = (data) => window.App.copy(data);
            navigator.clipboard.readText = () => window.App.paste();
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            navigator.setAppBadge = (data) => window.App.setAppBadge(data);
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            navigator.clearAppBadge = () => window.App.clearAppBadge();
            navigator.vibrate = (data) => window.App.vibrate(data);

            window.App.on('position', location => {
                if (positionCallbacks.length) {
                    positionCallbacks.forEach(obj => obj.callback(location));
                } else {
                    window.App.watchPosition(false);
                }
            })
            navigator.geolocation.watchPosition = (callback, errorCallback, options) => {
                const watchId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
                if (!positionCallbacks.length) {
                    window.App.watchPosition(true, options).then(callback).catch(errorCallback);
                }
                positionCallbacks.push({
                    id: watchId,
                    callback,
                });
                return watchId
            }
            navigator.geolocation.clearWatch = (watchId) => {
                positionCallbacks.filter((cb, i, arr) => {
                    if (cb.id == watchId) {
                        arr.splice(i, 1);
                        return true;
                    } else {
                        return false;
                    }
                })
                if (!positionCallbacks.length) {
                    window.App.watchPosition(false);
                }
            }
            navigator.geolocation.getCurrentPosition = (callback, errorCallback, settings) => window.App.getCurrentPosition(settings).then(callback).catch(errorCallback)
        }

        window.select = function (params: any) {
            return App.select(params).then((files: any) => {
                const dataTransfer = new DataTransfer();
                for (const file of files) {
                    const bytes = atob(file.data);
                    let length = bytes.length;
                    const out = new Uint8Array(length);

                    // Loop and convert.
                    while (length--) {
                        out[length] = bytes.charCodeAt(length);
                    }
                    dataTransfer.items.add(new File([out], file.name, { type: file.type }));
                }
                return dataTransfer;
            });
        };
    }

    document.addEventListener('DOMContentLoaded', () => {
        try {
            const viewport = getMeta('viewport');
            const keyboardResize = !!viewport && viewport.includes('interactive-widget=resizes-content');
            const appBarOffset = !!viewport && !viewport.includes('viewport-fit=cover');
            const navBarOffset = !!viewport && !viewport.includes('viewport-fit=cover');
            const backgroundColor = parseInt(getMeta('theme-color')!.substring(1), 16);
            const appBarColor = parseInt(getMeta('app-bar-color')!.substring(1), 16);
            const navBarColor = parseInt(getMeta('nav-bar-color')!.substring(1), 16);

            window.App.updateAppStyle({
                backgroundColor,
                appBarColor,
                navBarColor,
                appBarOffset,
                navBarOffset,
                keyboardResize,
            });
        } catch (e) {
            // eslint-disable-next-line no-console
            console.error('Unable to update app style', e);
        }
    }, false);
}
const App: IApp = window.App;
export default App;
