package it.integry.integrywmsnative.core.context;

import android.content.Context;
import android.text.Html;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.SpannedString;

import com.google.firebase.installations.FirebaseInstallations;

import java.net.ConnectException;

import javax.inject.Singleton;

import it.integry.integrywmsnative.core.barcode_reader.BarcodeManager;
import it.integry.integrywmsnative.core.data_store.db.AppDatabase;
import it.integry.integrywmsnative.core.menu.MenuService;
import it.integry.integrywmsnative.core.rest.consumers.SystemRESTConsumer;
import it.integry.integrywmsnative.core.rest.watcher.ServerStatusChecker;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityThread;

@Singleton
public class MainContext {

    private final Context applicationContext;
    private final MenuService menuService;
    private final AppDatabase appDatabase;
    private final SystemRESTConsumer systemRESTConsumer;

    private Listener mListener;

    public MainContext(Context applicationContext, MenuService menuService, AppDatabase appDatabase, SystemRESTConsumer systemRESTConsumer) {
        this.applicationContext = applicationContext;
        this.menuService = menuService;
        this.appDatabase = appDatabase;
        this.systemRESTConsumer = systemRESTConsumer;
    }

    public void init() {

        try {
            BarcodeManager.init(applicationContext);
        } catch (Exception exception) {
            exception.printStackTrace();
        }


        this.initDeviceId(() -> {
            this.initDBData(() -> {
                this.initMenu(() -> {

                    if (mListener != null) mListener.onContextInitialized();
                });
            });
        });


        this.initServerStatusChecker();

    }


    private void initDeviceId(Runnable onComplete) {
        if (SettingsManager.i().getUserSession().getDeviceId() != null) {
            onComplete.run();
            return;
        }


        FirebaseInstallations.getInstance().getId().addOnCompleteListener(fid -> {
            SettingsManager.i().getUserSession().setDeviceId(fid.getResult());
            SettingsManager.update();

            systemRESTConsumer.registerDevice(onComplete, ex -> {
                if (mListener != null) mListener.onError(new SpannedString(ex.getMessage()));
            });
        });
    }


    public void logout(Runnable onLoggedOut) {
        menuService.invalidateCache();
        UtilityThread.executeParallel(() -> {
            SettingsManager.i().setUser(null);
            SettingsManager.i().setUserSession(null);
            SettingsManager.update();
            appDatabase.clearAllTables();

            onLoggedOut.run();
        }, true);
    }

    private void initServerStatusChecker() {
        ServerStatusChecker.init();
    }

    private void initDBData(Runnable onComplete) {


        SettingsManager.loadDBVariables(item -> {
                    if (mListener != null) mListener.onDBDataLoading(item);
                },
                onComplete,
                ex -> {

                    Spanned message = null;

                    if (ex.getCause() != null && ex.getCause() instanceof ConnectException) {
                        message = Html.fromHtml("Impossibile collegarsi all'host <b>" + SettingsManager.i().getServer().getHost() + ":" + SettingsManager.i().getServer().getPort() + "</b>. Riprovare più tardi.");
                    } else if (ex.getMessage().startsWith("Status 404:")) {
                        message = Html.fromHtml("Errore 404. Non è stato possibile soddisfare la richiesta sull'host <b>" + SettingsManager.i().getServer().getHost() + ":" + SettingsManager.i().getServer().getPort() + "</b>. Riprovare più tardi.");
                    } else {
                        message = new SpannableString(ex.getMessage());
                    }

                    if (mListener != null) mListener.onError(message);

                }
        );
    }

    private void initMenu(Runnable onComplete) {
        if (mListener != null) mListener.onMenuLoading();
        this.menuService.init(onComplete, ex -> {
            if (mListener != null) mListener.onError(new SpannedString(ex.getMessage()));
        });
    }


    public MainContext setListener(Listener listener) {
        this.mListener = listener;
        return this;
    }

    public interface Listener {
        void onDBDataLoading(String item);

        void onMenuLoading();

        void onContextInitialized();

        void onError(Spanned message);
    }
}
