package cordova.plugin.netcontroll.integration;

// import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaWebView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;


import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.AsyncTask;

import com.elgin.e1.Balanca.BalancaE1;
import com.elgin.e1.Display.E1_Display;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.izettle.html2bitmap.Html2Bitmap;
import com.izettle.html2bitmap.content.WebViewContent;


import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.appcompat.app.AppCompatActivity;

import androidx.core.content.ContextCompat;

import android.app.Activity;
// import android.graphics.Bitmap;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
// import android.util.Log;
// import android.widget.Toast;
// import android.net.Uri;
// import android.content.Intent;
// import android.provider.MediaStore;
import android.os.Build;

// import static android.app.Activity.RESULT_OK;

import java.util.HashMap;
import java.util.Map;

// import javax.security.auth.callback.Callback;

import java.util.List;

//Json Serialize
import com.google.gson.Gson;
// import com.google.gson.GsonBuilder;





import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
// import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.common.BitMatrix;

//Bitmap
// import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
// import android.graphics.Matrix;

import android.os.Environment;
import android.util.Base64;
import java.io.ByteArrayOutputStream;
// import java.util.Objects;
// import java.util.stream.Collectors;


// import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.EnumMap;
// import java.util.HashMap;
// import java.util.Map;

//Elgin M10 Sdk

import com.elgin.e1.Impressora.Termica;

import javax.security.auth.callback.Callback;

import br.com.itfast.tectoy.Dispositivo;

public class ElginM10Terminal {
    //Cordova/Java Params
    private Activity mActivity;
    private Context mContext;
    private CordovaWebView webView;

    //Intents CODES
    private static int REQ_CODE_SELECAOIMAGEM = 1234;

    //CallbacksOnActivityResult
    private CallbackContext selecionarImagemCallbackContext;

    //cutPaper boolean for resultActivity
    private boolean cutPaper = false;


    private String ModelBalanca;
    private int Protocol;
    private int SerialBaudrate;
    private int SerialLength;
    private char SerialParity;
    private int SerialStopbits;
    private E1_Display imin;

    private int TamanhoBobina;

    private int RotacionarImpresso;

    private int ImpressoraExterna;
    private int abrirGaveta;

    String[] permissions = new String[]{
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
    };

    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        this.webView = webView;
        mActivity = cordova.getActivity();
        mContext = cordova.getActivity().getApplicationContext();

        //Initialize printer
//        Termica.setContext(mActivity);
        Termica.setActivity(mActivity);
    }

    public String Teste() {
        return "Result - ElginClass: ok";
    }

    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if (action.equals("AbreConexaoImpressora")) {
            try {
                JSONObject params = args.getJSONObject(0);

                int tipo = params.getInt("tipo");
                String modelo = params.getString("modelo");
                String modeloDispositivo = params.getString("modeloDispositivo");
                modeloDispositivo = modeloDispositivo.toUpperCase();
                String conexao = params.getString("conexao");
                int parametro = params.getInt("parametro");
                String velocidade = params.getString("velocidade");
                DefineTamanhoBobina(modeloDispositivo, velocidade);
                printerStop();
                int result = Termica.AbreConexaoImpressora(tipo, modelo, conexao, parametro);
                if (tipo == 1){
                    ImpressoraExterna = 1;
                } else {
                    ImpressoraExterna = 0;
                }
                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("AbreConexaoImpressora error: " + e.toString());
            }
            return true;
        } else if (action.equals("FechaConexaoImpressora")) {
            try {
                int result = Termica.FechaConexaoImpressora();
                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("FechaConexaoImpressora error: " + e.toString());
            }
            return true;
        } else if (action.equals("AvancaPapel")) {
            try {
                JSONObject params = args.getJSONObject(0);

                int linhas = params.getInt("linhas");

                int result = Termica.AvancaPapel(linhas);

                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("AvancaPapel error: " + e.toString());
            }
            return true;
        } else if (action.equals("Corte")) {
            try {
                JSONObject params = args.getJSONObject(0);

                int avanco = params.getInt("avanco");

                int result = Termica.Corte(avanco);

                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("Corte error: " + e.toString());
            }
            return true;
        } else if (action.equals("ImpressaoTexto")) {
            try {
                JSONObject params = args.getJSONObject(0);

                String dados = params.getString("dados");
                int posicao = params.getInt("posicao");
                int stilo = params.getInt("stilo");
                int tamanho = params.getInt("tamanho");

                int result = Termica.ImpressaoTexto(dados, posicao, stilo, tamanho);

                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("ImpressaoTexto error: " + e.toString());
            }
            return true;
        } else if (action.equals("ImpressaoCodigoBarras")) {
            try {
                JSONObject params = args.getJSONObject(0);

                int tipo = params.getInt("tipo");
                String dados = params.getString("dados");
                int altura = params.getInt("altura");
                int largura = params.getInt("largura");
                int HRI = params.getInt("HRI");

                int result = Termica.ImpressaoCodigoBarras(tipo, dados, altura, largura, HRI);

                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("ImpressaoCodigoBarras error: " + e.toString());
            }
            return true;
        } else if (action.equals("DefinePosicao")) {
            try {
                JSONObject params = args.getJSONObject(0);

                int posicao = params.getInt("posicao");

                int result = Termica.DefinePosicao(posicao);

                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("DefinePosicao error: " + e.toString());
            }
            return true;
        } else if (action.equals("ImpressaoQRCode")) {
            try {
                JSONObject params = args.getJSONObject(0);

                String dados = params.getString("dados");
                int tamanho = params.getInt("tamanho");
                int nivelCorrecao = params.getInt("nivelCorrecao");

                int result = Termica.ImpressaoQRCode(dados, tamanho, nivelCorrecao);

                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("ImpressaoQRCode error: " + e.toString());
            }
            return true;
        } else if (action.equals("ImprimeXMLNFCe")) {
            try {
                JSONObject params = args.getJSONObject(0);

                String dados = params.getString("dados");
                int indexcsc = params.getInt("indexcsc");
                String csc = params.getString("csc");
                int param = params.getInt("param");

                int result = Termica.ImprimeXMLNFCe(dados, indexcsc, csc, param);

                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("ImprimeXMLNFCe error: " + e.toString());
            }
            return true;
        } else if (action.equals("ImprimeXMLSAT")) {
            try {
                JSONObject params = args.getJSONObject(0);

                String dados = params.getString("dados");
                int param = params.getInt("param");

                int result = Termica.ImprimeXMLSAT(dados, param);

                callbackContext.success(result);

            } catch (Exception e) {
                callbackContext.error("ImprimeXMLSAT error: " + e.toString());
            }
            return true;
        } else if (action.equals("AbreGavetaElgin")) {
            try {
                int result = Termica.AbreGavetaElgin();

                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("AbreGavetaElgin error: " + e.toString());
            }
            return true;
        } else if (action.equals("ConfigurarBalanca")) {
            try {
                JSONObject params = args.getJSONObject(0);

                this.ModelBalanca = params.getString("modelBalanca");
                this.Protocol = params.getInt("protocol");
                this.SerialBaudrate = params.getInt("serialBaudrate");
                this.SerialLength = params.getInt("serialLength");
                this.SerialParity = params.getString("serialParity").charAt(0);
                this.SerialStopbits = params.getInt("serialStopbits");

                int MODEL = 0;
                switch (this.ModelBalanca) {
                    case "DP30CK":
                        MODEL = 0;
                        break;
                    case "SA110":
                        MODEL = 1;
                        break;
                    case "DPSC":
                        MODEL = 2;
                        break;
                    default:
                        MODEL = 0;
                }

                int retorno1 = BalancaE1.ConfigurarModeloBalanca(MODEL);
                int retorno2 = BalancaE1.ConfigurarProtocoloComunicacao(this.Protocol);

                callbackContext.success(String.format("\nConfigurarModeloBalanca: %d\nConfigurarProtocoloComunicacao: %d", retorno1, retorno2));
            } catch (Exception e) {
                callbackContext.error("ConfigurarBalanca error: " + e.toString());
            }
            return true;
        } else if (action.equals("LerPesoBalanca")) {
            try {
                if (this.ModelBalanca == null || this.ModelBalanca == "") {
                    callbackContext.error("LerPesoBalanca error: Balança não configurada");
                    return false;
                }
                int retorno1 = BalancaE1.AbrirSerial(this.SerialBaudrate, this.SerialLength, this.SerialParity, this.SerialStopbits); // Configuracao serial da balanca...
                String retorno2 = BalancaE1.LerPeso(1);
                int retorno3 = BalancaE1.Fechar();
                if (retorno1 == 0) {
                    callbackContext.success(retorno2);
                } else {
                    callbackContext.error(String.format("\nAbrirSerial: %d\nLerPeso: %s\nFechar: %d", retorno1, retorno2, retorno3));
                    return false;
                }
            } catch (Exception e) {
                callbackContext.error("StatusImpressora error: " + e.toString());
            }
            return true;
        } else if (action.equals("StatusImpressora")) {
            try {
                JSONObject params = args.getJSONObject(0);

                int param = params.getInt("param");

                int result = Termica.StatusImpressora(param);

                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("StatusImpressora error: " + e.toString());
            }
            return true;
        } else if (action.equals("ImprimeImagemBase64")) {
            try {
                JSONObject params = args.getJSONObject(0);
                String base64String = params.getString("base64String");
                int result = 0;
                String base64Image = base64String.split(",")[1];
                byte[] decodedString = Base64.decode(base64Image, Base64.DEFAULT);
                Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
                result = Termica.ImprimeBitmap(decodedByte);
                if (result == 1) {
                    // // //     if (this.cutPaper) {
                    // // //         result = Termica.Corte(avanco);
                    // // //     }
                }
                // // // // callbackContext.success(decodedString);
                callbackContext.success(result);
            } catch (Exception e) {
                callbackContext.error("AbreGavetaElgin error: " + e.toString());
            }
            return true;

            // try{
            //     JSONObject params = args.getJSONObject(0);

            //     if(params.getBoolean("cutPaper")) {
            //         this.cutPaper = true;  
            //     } 
            //     else {
            //         this.cutPaper = false;
            //     }

            //     String base64String = params.getString("base64String");
            //     // String base64Image = base64String.split(",")[1];
            //     // byte[] decodedString = Base64.decode(base64Image, Base64.DEFAULT);
            //     // Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);

            //     // Intent intent = new Intent((Intent.ACTION_PICK));
            //     // intent.setType("image/*");

            //     // this.selecionarImagemCallbackContext = callbackContext;

            //     // this.cordova.setActivityResultCallback(this);

            //     // this.cordova.getActivity().startActivityForResult(intent, REQ_CODE_SELECAOIMAGEM);
            //     // callbackContext.success(result);
            // }catch (Exception e){
            //     callbackContext.error("ImprimirImagem error: " + e.toString());
            // }
            // return true;
        } else if (action.equals("ImpressaoTextoNetPrint")) {
            JSONObject params = args.getJSONObject(0);
            try {
                String dados = params.getString("dados");
                Boolean negrito = false;
                try {
                    negrito = params.getBoolean("negrito");
                } catch (Exception ex) {
                }
                
                boolean abrirGavetaImp = cordova.plugin.netcontroll.integration.util.NetControllPrinter.EnviarAberturaGaveta(dados);
                String html = cordova.plugin.netcontroll.integration.util.NetControllPrinter.ConverterTextoImpressoToHtml(dados, negrito);
//                int ret = Termica.AvancaPapel(1);
//                if (ret != 0) {
//                    callbackContext.error("Erro ao avancar papel: " + ret);
//                    return false;
//                }
                cordova.plugin.netcontroll.integration.util.NetControllPrinter.ConverterHtmlToBitmap(html, mContext, bitmap -> {

                    if (this.TamanhoBobina >= 1) {
                        bitmap = cordova.plugin.netcontroll.integration.util.NetControllPrinter.ResizeBitmap(bitmap, 540);
                    }
                    if (this.RotacionarImpresso >= 1) {
                        bitmap = cordova.plugin.netcontroll.integration.util.NetControllPrinter.RotacionarBitmap(bitmap,180);
                    }
                    try {
                        Termica.DefinePosicao(1);
                    } catch (Exception ignored){}

                    if (bitmap != null) {
                        try {
                            int retPrint = 1;
                            if (this.ImpressoraExterna == 1){
                                retPrint = Termica.ImprimeImagem(bitmap);
                                try {
                                    Termica.AvancaPapel(15);
                                } catch (Exception ignored){}
                                
                            } else {
                                retPrint = Termica.ImprimeBitmap(bitmap);
                            }
                            if (retPrint != 0) {
                                callbackContext.error("Erro ao Imprimir bitmap: " + retPrint);
                                return;
                            } else {
                                callbackContext.success("Impresso Ok");
                            }
                        } catch (Exception errorPost) {
                            callbackContext.error("Result - ConverterHtmlToBitmap: " + "Error Detail: " + errorPost);
                        }
                        if (abrirGaveta == 1 && abrirGavetaImp) {
                            Termica.AbreGavetaElgin();
                        }
                    }
                });
            } catch (Exception e) {
                callbackContext.error("ImpressaoTextoNetPrint error: " + e.toString());
            }
            return true;
        } else if (action.equals("ImpressaoBase64NetPrint")) {
            try {
                JSONObject params = args.getJSONObject(0);
                String base64String = params.getString("base64String");
                Bitmap dadosBmp = cordova.plugin.netcontroll.integration.util.NetControllPrinter.ConverterBase64ToBitmap(base64String);
                //dadosBmp = cordova.plugin.netcontroll.integration.util.NetControllPrinter.ResizeBitmap(dadosBmp, 100);
                int retPrint = Termica.ImprimeBitmap(dadosBmp);
                if (retPrint != 0) {
                    callbackContext.error("Erro ao Imprimir bitmap: " + retPrint);
                } else {
                    callbackContext.success("Impresso Base64 Ok");
                }
            } catch (Exception e) {
                callbackContext.error("PrintTesteBase64 error: " + e.toString());
            }
            return true;

        } else if (action.equals("InicializaDisplay")) {
            try {
                imin.init(this.mActivity, E1_Display.DisplayDevices.TPRO);

                if(ContextCompat.checkSelfPermission(this.mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
                    ActivityCompat.requestPermissions(this.mActivity, permissions, 0);
                }
                int result = -1;
                result = imin.InicializaDisplay();
                if (result != 0) {
                    callbackContext.error("Erro ao iniciar o display");
                } else {
                    callbackContext.success("InicializaDisplay Ok");
                }
            } catch (Exception e) {
                callbackContext.error("InicializaDisplay error: " + e.toString());
            }
            return true;

        } else if (action.equals("ApresentaImagemDisplayBitmap")) {
            JSONObject params = args.getJSONObject(0);
            try {
                String dados = params.getString("dados");
                cordova.plugin.netcontroll.integration.util.NetControllPrinter.ConverterHtmlToBitmap(dados, mContext, bitmap -> {
                    if (bitmap != null) {
                        try {
                            int retorno = -1;
                            if (bitmap != null) {
                                retorno = imin.ApresentaImagemDisplay(bitmap);
                            }
                            if (retorno != 0) {
                                callbackContext.error("Erro ao Exibir img bitmap: " + retorno);
                            } else {
                                callbackContext.success("ApresentaImagemDisplayBitmap Ok");
                            }
                        } catch (Exception errorPost) {
                            callbackContext.error("Result - ApresentaImagemDisplayBitmap: " + "Error Detail: " + errorPost);
                        }
                    }
                }, 880, 120);
            } catch (Exception e) {
                callbackContext.error("ApresentaImagemDisplayBitmap error: " + e.toString());
            }
        }
        return true;
    }

    private void DefineTamanhoBobina(String dispositivoTypeName, String velocidade) {
        int velocidadeInt = 3; // valor padrão caso a conversão falhe
        try {
            velocidadeInt = Integer.parseInt(velocidade);
        } catch (NumberFormatException e) {}
        switch (dispositivoTypeName) {
            case "DESCONHECIDO":
            case "M10":
                this.abrirGaveta = 1;
                this.TamanhoBobina = 0;
                Termica.DefineDensidade(3);
                this.RotacionarImpresso = 0;
                break;
            case "I7 PlUS":
            case "I8":
            case "I9":
            case "IX":
            case "FITPOS":
            case "BK-T681":
            case "MP-4200":
            case "MP-4200 HS":
            case "MP-2800":
                this.abrirGaveta = 1;
                this.TamanhoBobina = 1;
                Termica.DefineDensidade(3);
                this.RotacionarImpresso = 0;
                break;
            case "POSGO":
                this.abrirGaveta = 1;
                this.TamanhoBobina = 1;
                try {
                    Termica.DefineDensidade(velocidadeInt);
                } catch (Exception e) {
                    Termica.DefineDensidade(3);
                }
                this.RotacionarImpresso = 1;
                break;
            case "MK":
                this.abrirGaveta = 0;
                this.TamanhoBobina = 1;
                try {
                    Termica.DefineDensidade(velocidadeInt);
                } catch (Exception e) {
                    Termica.DefineDensidade(3);
                }
                this.RotacionarImpresso = 1;
            break;
        }

    }
    public void printerStop() {
        Termica.FechaConexaoImpressora();
    }
}