package cordova.plugin.netcontroll.integration.banese;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.Log;

import androidx.annotation.Nullable;

import com.google.gson.Gson;

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 java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import ger7.com.br.pos7api.POS7API;
import ger7.com.br.pos7api.ParamIn;
import ger7.com.br.pos7api.ParamOut;
import br.com.positivo.printermodule.Printer;
import br.com.positivo.printermodule.PrinterCallback;

public class BanesePOS {
    //Cordova/Java Params
    private Activity mActivity;
    private Context mContext;
    private CordovaInterface mCordova;
    private CordovaWebView mWebView;

    //Banese
    private POS7API pos7api;
    private ParamIn entrada;
    private ParamOut saida;

    private int parcelas = 1;
    private int tipoTransacao = 0;
    private int tipoParcela = 1;
    private int valorTotal = 0;
    private String idPedido = null;
    private String pedidoComprovante = null;

    private Printer mPrinter;


    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        mActivity = cordova.getActivity();
        mContext = cordova.getActivity().getApplicationContext();
        mCordova = cordova;
        mWebView = webView;

        try {
            mPrinter = new Printer(this.mContext);

            mPrinter.setPrinterSpeed(5,new PrinterCallback(){
                @Override
                public void onError(int i, String s) {
                }

                @Override
                public void onRealLength(double v, double v1) {
                }

                @Override
                public void onComplete() {
                }
            });
        } catch (Exception e) {
        }
    }

    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        String callbackContextMessageBase = "Result Banese POS - " + action + ": ";
        if (action.equals("IniciarTransacao")) {
            JSONObject params = args.getJSONObject(0);
            try {
                String parcelasStr = params.getString("parcelas");
                String tipoTransacaoStr = params.getString("tipoPagamento");
                String valorSrt = params.getString("valor");
                Boolean imprimirComprovante = params.getBoolean("imprimirComprovante");
                try {
                    parcelas = Integer.parseInt(parcelasStr);
                } catch (Exception ignored) {
                }

                int valor = -1;
                try {
                    valor = Integer.parseInt(valorSrt.replace(",", "").replace(".", ""));
                } catch (Exception ignored) {
                }

                try {
                    tipoTransacao = Integer.parseInt(tipoTransacaoStr);
                } catch (Exception ignored) {
                }

                try {
                    pos7api = new POS7API(this.mContext);
                    entrada = new ParamIn();
                    idPedido =  new SimpleDateFormat("yyMMddHHmmss").format(new Date());

                    entrada.setTrsType(1);
                    entrada.setTrsAmount(String.valueOf(valor));
                    entrada.setTrsInstallments(parcelas);
                    entrada.setTrsProduct(tipoTransacao);
                    entrada.setTrsId(idPedido);
                    entrada.setTrsReceipt(imprimirComprovante);

                    pos7api.processTransaction(entrada, new POS7API.Pos7apiCallback() {
                        @Override
                        public void onResult(ParamOut saida) { //obtem os resultados da transação
                            processaResultado(saida, pedidoComprovante, callbackContext);
                        }
                    });
                } catch (Exception e) {
                    callbackContext.error("Result - Banese - L300 - IniciarTransacao: " + "Error Detail: " + e);
                }
                return true;
            } catch (Exception error1) {
                callbackContext.error("Result - Banese - L300 - IniciarTransacao: " + "Error Detail: " + error1);
            }
            return false;
        } else if (action.equals("CancelarTransacao")) {
            JSONObject params = args.getJSONObject(0);
            try {
                String tipoTransacaoStr = params.getString("tipoPagamento");
                String transacaoNsu = params.getString("transacaoNsu");
                boolean imprimirComprovante = params.getBoolean("imprimirComprovante");
                String valorSrt = params.getString("valor");
                int valor = -1;
                try {
                    valor = Integer.parseInt(valorSrt.replace(",", "").replace(".", ""));
                } catch (Exception ignored) {
                }

                try {
                    tipoTransacao = Integer.parseInt(tipoTransacaoStr);
                } catch (Exception ignored) {
                }

                try {
                    pos7api = new POS7API(this.mContext);
                    entrada = new ParamIn();
                    idPedido =  transacaoNsu;

                    entrada.setTrsType(2);
                    entrada.setTrsRefundId(idPedido);
                    entrada.setTrsProduct(tipoTransacao);
                    entrada.setTrsAmount(String.valueOf(valor));
                    entrada.setTrsReceipt(imprimirComprovante);
                    entrada.setMerchantPwd(false);

                    pos7api.processTransaction(entrada, new POS7API.Pos7apiCallback() {
                        @Override
                        public void onResult(ParamOut saida) { //obtem os resultados da transação
                            processaResultado(saida, pedidoComprovante, callbackContext);
                        }
                    });
                } catch (Exception e) {
                    callbackContext.error("Result - Banese - L300 - CancelarTransacao: " + "Error Detail: " + e);
                }
                return true;
            } catch (Exception error1) {
                callbackContext.error("Result - Banese - L300 - CancelarTransacao: " + "Error Detail: " + error1);
            }
            return false;
        } 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) {
                }

                String html = cordova.plugin.netcontroll.integration.util.NetControllPrinter.ConverterTextoImpressoToHtmlSemFundoPreto(dados, negrito);
                cordova.plugin.netcontroll.integration.util.NetControllPrinter.ConverterHtmlToBitmap(html, mContext,bitmapResult -> {
                    Bitmap dadosImg = bitmapResult;
                    dadosImg = convertTo1Bit(dadosImg);
                    try {
                        if (!mPrinter.isReady()){
                            wait(10000);
                        }

                        mPrinter.printBitmap(dadosImg, new PrinterCallback() {
                            @Override
                            public void onError(int i, String s) {
                                callbackContext.error("Banese - L300 - ImpressaoTextoNetPrintImg error: " + i);
                            }
                            @Override
                            public void onRealLength(double v, double v1) {
                                try {
                                    wait(1000);
                                } catch (InterruptedException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                            @Override
                            public void onComplete() {
                                mPrinter.printWrapPaper(5, new PrinterCallback() {
                                    @Override
                                    public void onError(int i, String s) {
                                    }
                                    @Override
                                    public void onRealLength(double v, double v1) {
                                    }
                                    @Override
                                    public void onComplete() {
                                    }
                                });
                                callbackContext.success(callbackContextMessageBase + "Success");
                            }
                        });
                    } catch (Exception e) {
                        callbackContext.error("Banese - L300 - ImpressaoTextoNetPrintImg error: " + e);
                    }
                },380,94);
            } catch (Exception e) {
                callbackContext.error("Banese - L300 - ImpressaoTextoNetPrintImg error: " + e);
            }
            return true;
        } else if (action.equals("RetornaUUIDMifare")) {
            try {
                JSONObject params = args.getJSONObject(0);
                String statusChangeCallBack = params.getString("statusChangeCallBack");

                // new Thread(() -> {
                //     long startTime = System.currentTimeMillis();
                //     long timeout = 60000; // 60 segundos
                //     boolean cardDetected = false;

                //     while (!cardDetected && (System.currentTimeMillis() - startTime) < timeout) {
                //         CountDownLatch latch = new CountDownLatch(1);
                //         AtomicReference<MifareResult> resultRef = new AtomicReference<>();

                //         Mifare.detectCards(detectCardsResult -> {
                //             resultRef.set(detectCardsResult);
                //             latch.countDown();
                //             return null;
                //         });

                //         try {
                //             // Aguardar resultado por até 1 segundo
                //             latch.await(1000, TimeUnit.MILLISECONDS);

                //             MifareResult result = resultRef.get();
                //             if (result instanceof MifareResult.Success) {
                //                 cardDetected = true;

                //                 // Processar UUID
                //                 List<Byte> byteUUID = ((MifareResult.Success) result)
                //                         .getCardInfo().getSerialNumber();
                //                 StringBuilder strUUID = new StringBuilder();
                //                 for (byte b : byteUUID) {
                //                     strUUID.append(String.format("%02X", b));
                //                 }

                //                 callbackContext.success(strUUID.toString().toUpperCase());
                //             }

                //             // Aguardar um pouco antes da próxima tentativa
                //             if (!cardDetected) {
                //                 Thread.sleep(500);
                //             }

                //         } catch (InterruptedException e) {
                //             Thread.currentThread().interrupt();
                //             callbackContext.error("Erro na leitura do cartão!");
                //             return;
                //         }
                //     }

                //     if (!cardDetected) {
                //         callbackContext.error("Erro na leitura do cartão!");
                //     }
                // }).start();
                String Status = "Aproxime o cartão NFC a leitora NFC!";
                executeGlobalJavascript(statusChangeCallBack + "('" + Status + "')");

                return true;
            } catch (Exception error1) {
                callbackContext.error("Result - Banese - RetornaUUIDMifare: " + "Error Detail: " + error1);
            }
        } else if (action.equals("FechaComunicacaoMifare")) {
            try {

                // Mifare.powerOff(powerOffResult -> {
                //     if (powerOffResult instanceof MifareResult.Success) {
                //         callbackContext.success("Antena Mifare desativada");
                //     } else if (powerOffResult instanceof MifareResult.Error) {
                //         callbackContext.success("Antena Mifare desativada");
                //     }
                //     return null;
                // });
                return true;
            } catch (Exception error1) {
                callbackContext.error("Result - Banese - CancelaComunicacaoMifare: " + "Error Detail: " + error1);
            }
        }
        return false;
    }


    private void processaResultado(ParamOut resultado, @Nullable String dadosExtra, CallbackContext callbackContext) {

        int codigo = resultado.getResponse();
        String mensagem = "";
        String comprovante = "";

        switch (codigo) {
            case 0: // aprovado
                try {
                    Map<String, Object> response = new HashMap<>();
                    Map<String, String> statusResp = new HashMap<>();

                    statusResp.put("codigo", String.valueOf(codigo));
                    statusResp.put("mensagem", "Transação aprovada.");
                    try {
                        if (resultado.getStatus() == 0) {
                            statusResp.put("status", "Pronto para transacionar.");
                        } else {
                            statusResp.put("status", "Não pronto para transacionar (não configurado, não parametrizado, não instalado, sem licença válida ou com defeito interno).");
                        }
                    } catch (Exception e) {
                    }

                    response.put("statusResp", statusResp);

                    // Pega os campos do JSONObject (como string) e insere no mapa
                    response.put("bandeira", resultado.getResLabel().toUpperCase().trim());
                    try {
                        String[] comprovantes = resultado.getResPrint().split("\f");
                        response.put("viaCliente", comprovantes[0]);
                        response.put("viaEstab", comprovantes[1]);
                    } catch (Exception e) {
                        response.put("viaCliente", resultado.getResPrint());
                    }
                    response.put("idTransacao", resultado.getResId());
                    //response.put("nsu", resultado.getResStan());
                    response.put("nsu", resultado.getResRrn());
                    response.put("cAut", resultado.getResAuthorization());

                    String jsonResponse = new Gson().toJson(response);
                    callbackContext.success(jsonResponse);
                } catch (Exception e) {
                }
                break;

            case 1: // negado
                try {
                    Map<String, String> statusResp = new HashMap<>();

                    statusResp.put("codigo", String.valueOf(codigo));
                    statusResp.put("mensagem", "Transação negada (pelo autorizador, pelo cartão ou pelo POS).");
                    try {
                        if (resultado.getStatus() == 0) {
                            statusResp.put("status", "Pronto para transacionar.");
                        } else {
                            statusResp.put("status", "Não pronto para transacionar (não configurado, não parametrizado, não instalado, sem licença válida ou com defeito interno).");
                        }
                    } catch (Exception e) {
                    }

                    String jsonResponse = new Gson().toJson(statusResp);
                    callbackContext.error(jsonResponse);
                } catch (Exception e) {
                }
                break;

            case 2:
                try {
                    Map<String, String> statusResp = new HashMap<>();

                    statusResp.put("codigo", String.valueOf(codigo));
                    statusResp.put("mensagem", "Transação cancelada pelo usuário ou timeout de teclado.");
                    try {
                        if (resultado.getStatus() == 0) {
                            statusResp.put("status", "Pronto para transacionar.");
                        } else {
                            statusResp.put("status", "Não pronto para transacionar (não configurado, não parametrizado, não instalado, sem licença válida ou com defeito interno).");
                        }
                    } catch (Exception e) {
                    }
                    String jsonResponse = new Gson().toJson(statusResp);
                    callbackContext.error(jsonResponse);
                } catch (Exception e) {
                }
                break;

            case 3:
                try {
                    Map<String, String> statusResp = new HashMap<>();

                    statusResp.put("codigo", String.valueOf(codigo));
                    statusResp.put("mensagem", "Transação falhou (erro de comunicação, problemas com o cartão ou exceção no fluxo da transação).");
                    try {
                        if (resultado.getStatus() == 0) {
                            statusResp.put("status", "Pronto para transacionar.");
                        } else {
                            statusResp.put("status", "Não pronto para transacionar (não configurado, não parametrizado, não instalado, sem licença válida ou com defeito interno).");
                        }
                    } catch (Exception e) {
                    }
                    String jsonResponse = new Gson().toJson(statusResp);
                    callbackContext.error(jsonResponse);
                } catch (Exception e) {
                }
                break;

            case 4:
                try {
                    Map<String, String> statusResp = new HashMap<>();

                    statusResp.put("codigo", String.valueOf(codigo));
                    statusResp.put("mensagem", "O POS7 está em estado inválido (não configurada/parametrizada ou sem licença válida).");
                    try {
                        if (resultado.getStatus() == 0) {
                            statusResp.put("status", "Pronto para transacionar.");
                        } else {
                            statusResp.put("status", "Não pronto para transacionar (não configurado, não parametrizado, não instalado, sem licença válida ou com defeito interno).");
                        }
                    } catch (Exception e) {
                    }
                    String jsonResponse = new Gson().toJson(statusResp);
                    callbackContext.error(jsonResponse);
                } catch (Exception e) {
                }
                break;

            case 5:
                try {
                    Map<String, String> statusResp = new HashMap<>();

                    statusResp.put("codigo", String.valueOf(codigo));
                    statusResp.put("mensagem", "Transação indisponível nesta versão do POS7.");
                    try {
                        if (resultado.getStatus() == 0) {
                            statusResp.put("status", "Pronto para transacionar.");
                        } else {
                            statusResp.put("status", "Não pronto para transacionar (não configurado, não parametrizado, não instalado, sem licença válida ou com defeito interno).");
                        }
                    } catch (Exception e) {
                    }
                    String jsonResponse = new Gson().toJson(statusResp);
                    callbackContext.error(jsonResponse);
                } catch (Exception e) {
                }
                break;

            case 6: // PIX em processamento
                try {
                    Map<String, String> statusResp = new HashMap<>();

                    statusResp.put("codigo", String.valueOf(codigo));
                    statusResp.put("mensagem", "Pagamento PIX em processamento. Caso tenha o cliente tenha efetivado o pagamento, consultar pelo APP da ADIQ.");
                    try {
                        if (resultado.getStatus() == 0) {
                            statusResp.put("status", "Pronto para transacionar.");
                        } else {
                            statusResp.put("status", "Não pronto para transacionar (não configurado, não parametrizado, não instalado, sem licença válida ou com defeito interno).");
                        }
                    } catch (Exception e) {
                    }
                    String jsonResponse = new Gson().toJson(statusResp);
                    callbackContext.error(jsonResponse);
                } catch (Exception e) {
                }
                break;

            default:
                try {
                    callbackContext.error("Banese - L300 - Resultado da transação não mapeado, " + codigo + "." );
                } catch (Exception e) {
                }
                break;
        }
    }

    private static Bitmap convertTo1Bit(Bitmap original) {
        int width = original.getWidth();
        int height = original.getHeight();

        // Cria bitmap monocromático
        Bitmap bitmap1Bit = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

        int[] pixels = new int[width * height];
        original.getPixels(pixels, 0, width, 0, 0, width, height);

        // Threshold otimizado para texto
        int threshold = 128;

        for (int i = 0; i < pixels.length; i++) {
            int pixel = pixels[i];

            // Calcula luminância
            int r = Color.red(pixel);
            int g = Color.green(pixel);
            int b = Color.blue(pixel);
            int gray = (int)(0.299 * r + 0.587 * g + 0.114 * b);

            // Converte para preto ou branco puro
            pixels[i] = gray > threshold ? Color.WHITE : Color.BLACK;
        }

        bitmap1Bit.setPixels(pixels, 0, width, 0, 0, width, height);
        return bitmap1Bit;
    }

    private void executeGlobalJavascript(final String jsString) {
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mWebView.loadUrl("javascript:" + jsString);
            }
        });
    }
}