package it.integry.integrywmsnative.core.barcode_reader;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Pair;
import android.view.KeyEvent;

import androidx.preference.PreferenceManager;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;

import it.integry.barcode_base_android_library.interfaces.BarcodeReaderInterface;
import it.integry.barcode_base_android_library.model.BarcodeSetting;
import it.integry.honeywellscannerlibrary.HoneyWellBarcodeReader;
import it.integry.integrywmsnative.core.utility.UtilityLogger;
import it.integry.integrywmsnative.gest.settings.MainSettingsFragment;
import it.integry.keyobardemulatorscannerlibrary.KeyboardEmulatorBarcodeReader;
import it.integry.pointmobilescannerlibrary.PointMobileBarcodeReader;
import it.integry.zebrascannerlibrary.ZebraBarcodeReader;

public class BarcodeManager {

    private static BarcodeReaderInterface mCurrentBarcodeInterface;
    private static final List<BarcodeCallbackDTO> mBarcodeCallbacksStacktrace = new ArrayList<>();

    private static boolean mEnabled = true;


    private static final Class<? extends BarcodeReaderInterface>[] registeredBarcodeReaderInterfaces = new Class[]{PointMobileBarcodeReader.class, ZebraBarcodeReader.class, HoneyWellBarcodeReader.class, KeyboardEmulatorBarcodeReader.class};


    public static void init(Context applicationContext) throws Exception {

        initBarcodeReader(applicationContext);
    }

    private static void initBarcodeReader(Context applicationContext) throws Exception {

        for (Class<? extends BarcodeReaderInterface> readerInterface : registeredBarcodeReaderInterfaces) {

            Constructor<?> cons = Class.forName(readerInterface.getName()).getConstructors()[0];
            BarcodeReaderInterface object = (BarcodeReaderInterface) cons.newInstance(applicationContext);

            if (object.isRightAdapter()) {
                mCurrentBarcodeInterface = object;
                break;
            }


        }

        if (mCurrentBarcodeInterface != null) {

            mCurrentBarcodeInterface.init(() -> {

                mCurrentBarcodeInterface.register(data -> {
                    BarcodeCallbackDTO callback = getValidCallback();
                    if (callback != null && mEnabled) {
                        callback.getOnScanSuccessfull().run(data);
                    }
                }, ex -> {
                    BarcodeCallbackDTO callback = getValidCallback();
                    if (callback != null && mEnabled) {
                        callback.getOnScanFailed().run(ex);
                    }
                });

                SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext);
                var additionalSettings = new ArrayList<Pair<String, Object>>();
                var scanDelay = sharedPreferences.getString(MainSettingsFragment.KEY_TRIGGER_SCAN_DELAY, null);
                var scanDelaySetting = new Pair<String, Object>(BarcodeSetting.P_TRIGGER_SCAN_DELAY, scanDelay);
                additionalSettings.add(scanDelaySetting);

                var scanMode = sharedPreferences.getString(MainSettingsFragment.KEY_TRIGGER_SCAN_MODE, null);
                var scanModeSetting = new Pair<String, Object>(BarcodeSetting.P_TRIGGER_SCAN_MODE, scanMode);
                additionalSettings.add(scanModeSetting);
                
                BarcodeManager.changeSettings(additionalSettings);

            });
        }
    }


    private static BarcodeCallbackDTO getValidCallback() {

        if (mBarcodeCallbacksStacktrace.size() > 0) {
            return mBarcodeCallbacksStacktrace.get(mBarcodeCallbacksStacktrace.size() - 1);
        } else {
            return null;
        }

    }

    public static boolean onKeyDown(int keyCode, KeyEvent keyEvent) {
        if (mCurrentBarcodeInterface != null) mCurrentBarcodeInterface.onKeyEvent(keyEvent);
        return true;
    }

    public static BarcodeReaderInterface getCurrentBarcodeInterface() {
        return mCurrentBarcodeInterface;
    }

    public static int addCallback(BarcodeCallbackDTO barcodeCallbackDTO) {

        int newID = -1;

        if (mBarcodeCallbacksStacktrace.size() > 0) {
            newID = mBarcodeCallbacksStacktrace.get(mBarcodeCallbacksStacktrace.size() - 1).getID() + 1;
        } else {
            newID = 1;
        }

        barcodeCallbackDTO.setID(newID);
        mBarcodeCallbacksStacktrace.add(barcodeCallbackDTO);

        return newID;
    }

    public static void removeCallback(int ID) {
        boolean callbackObjFound = false;

        //Rimuovo la callback con l'ID trovato e tutte quelle con >ID in modo che rimuovo tutte le call aggiunte successivamente

        for (int i = 0; i < mBarcodeCallbacksStacktrace.size(); i++) {
            if (mBarcodeCallbacksStacktrace.get(i).getID() == ID || callbackObjFound) {
                mBarcodeCallbacksStacktrace.remove(i);

                callbackObjFound = true;
            }
        }
    }


    public static void disable() {
        mEnabled = false;
        UtilityLogger.trace("Barcode reader disabled");
    }

    public static void enable() {
        mEnabled = true;
        UtilityLogger.trace("Barcode reader enabled");
    }

    public static boolean isEnabled() {
        return mEnabled;
    }

    public static void changeSettings(List<Pair<String, Object>> settings) {
        mCurrentBarcodeInterface.changeSettings(settings);
    }

    public static boolean isKeyboardEmulator() {
        return mCurrentBarcodeInterface instanceof KeyboardEmulatorBarcodeReader;
    }
}
