package com.neptune.plugin;

import android.os.Handler;
import android.os.Looper;

import com.getcapacitor.JSObject;
import com.getcapacitor.PluginCall;
import com.neptune.modules.Scanner;
import com.neptune.utils.MyLog;
import com.pax.dal.IScanner;
import com.pax.dal.entity.EScannerType;

public class NeptuneScannerHandler {

    public static final String SCAN_CANCELLED = "SCAN_CANCELLED";
    public static final String SCAN_TIMEOUT = "SCAN_TIMEOUT";
    public static final String SCAN_ERROR = "SCAN_ERROR";

    private static final int DEFAULT_TIMEOUT = 30000;
    private static final int TIMEOUT_MARGIN = 5000;

    private static final Handler mainHandler = new Handler(Looper.getMainLooper());
    private static PluginCall pendingCall = null;
    private static Runnable timeoutTask = null;

    public static void scanStart(PluginCall call) {
        MyLog.logI("Starting scanStart");

        final int timeout;
        final EScannerType type;
        final boolean flash;
        try {
            JSObject value = call.getData().getJSObject("value", new JSObject());
            timeout = value.getInteger("timeout", DEFAULT_TIMEOUT);
            type = EScannerType.valueOf(value.getString("camera", EScannerType.REAR.name()));
            flash = value.getBoolean("flash", false);
        } catch (Exception e) {
            MyLog.logE(e.getMessage());
            call.reject("Invalid scan options: " + e.getMessage(), SCAN_ERROR);
            return;
        }

        synchronized (NeptuneScannerHandler.class) {
            if (pendingCall != null) {
                call.reject("Scan already in progress", SCAN_ERROR);
                return;
            }
            pendingCall = call;
        }

        mainHandler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    if (!Scanner.getInstance().open(type)) {
                        finish(null, SCAN_ERROR, "Scanner open failed");
                        return;
                    }
                    Scanner.getInstance().setTimeOut(timeout);
                    if (flash) {
                        Scanner.getInstance().setFlashOn(true);
                    }
                    timeoutTask = new Runnable() {
                        @Override
                        public void run() {
                            finish(null, SCAN_TIMEOUT, "Scan timeout");
                        }
                    };
                    mainHandler.postDelayed(timeoutTask, timeout + TIMEOUT_MARGIN);
                    Scanner.getInstance().start(new IScanner.IScanListener() {
                        @Override
                        public void onRead(String text) {
                            MyLog.logI("scanStart onRead");
                            finish(text, null, null);
                        }

                        @Override
                        public void onFinish() {
                            MyLog.logI("scanStart onFinish");
                            finish(null, SCAN_TIMEOUT, "Scan finished without read");
                        }

                        @Override
                        public void onCancel() {
                            MyLog.logI("scanStart onCancel");
                            finish(null, SCAN_CANCELLED, "Scan cancelled");
                        }
                    });
                } catch (Exception e) {
                    MyLog.logE(e.getMessage());
                    finish(null, SCAN_ERROR, String.valueOf(e.getMessage()));
                }
            }
        });
    }

    public static void scanCancel(PluginCall call) {
        MyLog.logI("Starting scanCancel");
        JSObject ret = new JSObject();
        try {
            finish(null, SCAN_CANCELLED, "Scan cancelled by app");
            ret.put("value", NeptuneErrors.NEPTUNE_ERR_OK.name());
            call.success(ret);
        } catch (Exception e) {
            MyLog.logE(e.getMessage());
            call.reject(e.getMessage(), e);
        }
    }

    // Resolves or rejects the pending scan only once and always closes the scanner
    private static void finish(String text, String code, String message) {
        PluginCall call;
        synchronized (NeptuneScannerHandler.class) {
            call = pendingCall;
            pendingCall = null;
            if (timeoutTask != null) {
                mainHandler.removeCallbacks(timeoutTask);
                timeoutTask = null;
            }
        }
        try {
            Scanner.getInstance().close();
        } catch (Exception e) {
            MyLog.logE("close: " + e.getMessage());
        }
        if (call == null) {
            return;
        }
        if (code == null) {
            JSObject ret = new JSObject();
            ret.put("value", text);
            call.success(ret);
        } else {
            MyLog.logI("scanStart " + code + ": " + message);
            call.reject(message, code);
        }
    }
}
