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 java.lang.reflect.Method;
import java.net.ConnectException;

import javax.inject.Singleton;

import it.integry.integrywmsnative.core.barcode_reader.BarcodeManager;
import it.integry.integrywmsnative.core.class_router.ClassRouter;
import it.integry.integrywmsnative.core.data_store.db.AppDatabase;
import it.integry.integrywmsnative.core.menu.MenuService;
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 Listener mListener;

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

    public void init() {

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

        }

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

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


        this.initServerStatusChecker();

    }

    public void logout(Runnable onLoggedOut) {
        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()));
        });
    }

    private void initReflections() {
        ClassRouter.init();

        try {
            String initMethod = "init";

            Class dynamicContextClass = Class.forName("it.integry.wms.dynamic_customization.DynamicContext");

            Method[] methods = dynamicContextClass.getMethods();
            for (Method m : methods) {
                if (initMethod.equals(m.getName())) {
                    // for static methods we can use null as instance of class
                    final Object newInstance = dynamicContextClass.newInstance();

                    m.invoke(newInstance, applicationContext);
                    break;
                }
            }

        } catch (Exception e) {
//            UtilityExceptions.defaultException(mContext, e, true);
        }
    }


    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);
    }
}
