package cordova.plugin.netcontroll.integration;

import static android.app.Activity.RESULT_CANCELED;
import static android.app.Activity.RESULT_OK;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.google.gson.Gson;
import com.xcheng.printerservice.IPrinterCallback;
import com.xcheng.printerservice.IPrinterService;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.List;
import java.util.Map;

import rede.smartrede.sdk.FlexTipoPagamento;
import rede.smartrede.sdk.Payment;
import rede.smartrede.sdk.PaymentStatus;
import rede.smartrede.sdk.RedePaymentValidationError;
import rede.smartrede.sdk.RedePayments;

public class RedeL400 implements RedeL400PrinterManager.PrinterManagerListener {
    //Impressora
    private RedeL400PrinterManager mPrinterManager;

    //Pagametnos
    private RedePayments redePayments;
    private static final int PAYMENT_REQUEST_CODE = 890001;
    private static final int REVERSAL_REQUEST_CODE = 890002;
    private static final int REPRINT_REQUEST_CODE = 890003;


    //Cordova/Java Params
    private Activity mActivity;
    private Context mContext;
    private CordovaInterface mCordova;
    private CordovaWebView mWebView;

    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        mActivity = cordova.getActivity();
        mContext = cordova.getActivity().getApplicationContext();
        mCordova = cordova;
        mWebView = webView;

        redePayments = RedePayments.getInstance(mActivity);
    }

    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        String callbackContextMessageBase = "Result Rede L400 - " + action + ": ";
        if (action.equals("Initialize")) {
            JSONObject params = args.getJSONObject(0);
            try {
                mPrinterManager = new RedeL400PrinterManager(this.mContext, this);
                mPrinterManager.onPrinterStart();
                callbackContext.success(callbackContextMessageBase + "Success");
                return true;
            } catch (Exception error) {
                callbackContext.error(callbackContextMessageBase + "Error Detail: " + error);
            }
        } else if (action.equals("IniciarPagamento")) {
            try {
                JSONObject params = args.getJSONObject(0);

                String tipoTransacao = params.getString("tipoTransacao");
                FlexTipoPagamento tipoTransacaoObj = GetFlexTipoPagamentoEnumByName(tipoTransacao);

                int valor = params.getInt("valor");
                int numeroParcelas = params.getInt("numeroParcelas");

                Intent collectPaymentIntent = redePayments
                        .intentForPaymentBuilder(tipoTransacaoObj, valor)
                        .setInstallments(numeroParcelas).build();

                CordovaPlugin paymentResultCordovaPlugin = new CordovaPlugin() {
                    @Override
                    public void onActivityResult(int requestCode, int resultCode, Intent data) {
                        if (requestCode == PAYMENT_REQUEST_CODE) {
                            if (resultCode == RESULT_OK) {
                                if (data != null) {
                                    Payment payment = RedePayments.getPaymentFromIntent(data);
                                    Gson gson = new Gson();
                                    if (payment.getStatus() == PaymentStatus.AUTHORIZED) {
                                        //Receipt receipt =  payment.getReceipt();
                                        // String varResultStrJson = NetControllHelpers.parseObjToJsonSrtring(payment);
                                        // callbackContext.success(varResultStrJson);
                                        // callbackContext.success("PAGAMENTO OK");

                                        String paymentJsonString = gson.toJson(payment);

                                        callbackContext.success(paymentJsonString);
                                        //                                        callbackContext.success(payment.toString());
                                    } else if (payment.getStatus() == PaymentStatus.FAILED) {
                                        callbackContext.success(gson.toJson(payment));
                                    } else if (payment.getStatus() == PaymentStatus.DECLINED) {
                                        callbackContext.success(gson.toJson(payment));
                                    }
                                }
                            } else if (resultCode == RESULT_CANCELED) {
                                callbackContext.error("Operação cancelada pelo usuário");
                            }
                        } else {
                            callbackContext.error("Pagamento result não encontrado");
                        }
                    }
                };
                mCordova.startActivityForResult(paymentResultCordovaPlugin, collectPaymentIntent, PAYMENT_REQUEST_CODE);
                return true;
            } catch (RedePaymentValidationError ex) {
                callbackContext.error("Pagamentos - Intent Pagamentos not found: " + ex);
            } catch (Exception e) {
                callbackContext.error("IniciarPagamento error: " + e);
            }
            return false;
        } else if (action.equals("EstornarPagamento")) {
            try {
                Intent reversal = redePayments.intentForReversal();
                CordovaPlugin reversalResultCordovaPlugin = new CordovaPlugin() {
                    @Override
                    public void onActivityResult(int requestCode, int resultCode, Intent data) {
                        if (requestCode == REVERSAL_REQUEST_CODE) {
                            if (resultCode == RESULT_OK) {
                                if (data != null) {
                                    Gson gson = new Gson();
                                    Payment payment = RedePayments.getPaymentFromIntent(data);
                                    if (payment.getStatus() == PaymentStatus.AUTHORIZED) {
                                        callbackContext.success(gson.toJson(payment));
                                    } else if (payment.getStatus() == PaymentStatus.FAILED) {
                                        callbackContext.success(gson.toJson(payment));
                                    } else if (payment.getStatus() == PaymentStatus.DECLINED) {
                                        callbackContext.success(gson.toJson(payment));
                                    }
                                }
                            } else if (resultCode == RESULT_CANCELED) {
                                callbackContext.error("Operação cancelada pelo usuário");
                            }
                        } else {
                            callbackContext.error("Estorno result não encontrado");
                        }
                    }
                };
                mCordova.startActivityForResult(reversalResultCordovaPlugin, reversal, REVERSAL_REQUEST_CODE);
                return true;
            } catch (RedePaymentValidationError ex) {
                callbackContext.error("Pagamentos - Intent Pagamentos not found: " + ex);
            } catch (Exception e) {
                callbackContext.error("IniciarPagamento error: " + e);
            }
            return false;
        } else if (action.equals("ReimprimirPagamento")) {
            try {
                Intent reprint = redePayments.intentForReprint();
                CordovaPlugin reprintResultCordovaPlugin = new CordovaPlugin() {
                    @Override
                    public void onActivityResult(int requestCode, int resultCode, Intent data) {
                        if (requestCode == REPRINT_REQUEST_CODE) {
                            if (resultCode == RESULT_OK) {
                                callbackContext.success("Reimpressão efetuada com sucesso");
                            } else if (resultCode == RESULT_CANCELED) {
                                callbackContext.error("Reimpressão cancelada pelo usuário");
                            }
                        } else {
                            callbackContext.error("Reimpressão result não encontrado");
                        }
                    }
                };
                mCordova.startActivityForResult(reprintResultCordovaPlugin, reprint, REPRINT_REQUEST_CODE);
                return true;
            } catch (RedePaymentValidationError ex) {
                callbackContext.error("Pagamentos - Intent Pagamentos not found: " + ex);
            } catch (Exception e) {
                callbackContext.error("IniciarPagamento error: " + e);
            }
            return false;
        } else if (action.equals("ImpressaoTextoNetPrint")) {
            JSONObject params = args.getJSONObject(0);
            try {
                validarPapel();
                String dados = params.getString("dados");
                Boolean negrito = false;
                try {
                    negrito = params.getBoolean("negrito");
                }catch (Exception ex){
                }
                String html = cordova.plugin.netcontroll.integration.util.NetControllPrinter.ConverterTextoImpressoToHtml(dados, negrito);
                cordova.plugin.netcontroll.integration.util.NetControllPrinter.ConverterHtmlToBitmap(html, mContext, bitmapResult -> {
                    Bitmap dadosImg = bitmapResult;
                    this.onImprimirBitmap(dadosImg);
                    callbackContext.success(callbackContextMessageBase + "Success");
                });
            } catch (Exception e) {
                callbackContext.error("ImpressaoTextoNetPrintImg error: " + e);
            }
            return true;
        } else if (action.equals("ImpressaoBase64NetPrint")) {
            try{
                validarPapel();
                JSONObject params = args.getJSONObject(0);
                String base64String = params.getString("base64String");

                Bitmap dadosImg = cordova.plugin.netcontroll.integration.util.NetControllPrinter.ConverterBase64ToBitmap(base64String);
                this.onImprimirBitmap(dadosImg);
                callbackContext.success(callbackContextMessageBase + "Success");
            } catch (Exception e){
                callbackContext.error("PrintTesteBase64 error: " + e.toString());
            }
            return true;
        }
        return false;
    }

    @Override
    public void onServiceConnected() {
        mPrinterManager.printerInit();
    }

    private void validarPapel() throws Exception {
        boolean temPapel = mPrinterManager.printerPaper();
        if (!temPapel) {
            throw new Exception("Impressora sem Papel");
        }
    }

    public void onImprimirBitmap(Bitmap bitmap) {
        try {
            mPrinterManager.printBitmap(bitmap);
            mPrinterManager.printText("\n\n\n\n\n");
        } catch (Exception ex) {
            throw ex;
        }
    }


    private FlexTipoPagamento GetFlexTipoPagamentoEnumByName(String receiptTypeName) {
        FlexTipoPagamento flexTipoPagamento = FlexTipoPagamento.CREDITO_A_VISTA;
        switch (receiptTypeName) {
            case "CREDITO_A_VISTA":
                flexTipoPagamento = FlexTipoPagamento.CREDITO_A_VISTA;
                break;
            case "CREDITO_PARCELADO":
                flexTipoPagamento = FlexTipoPagamento.CREDITO_PARCELADO;
                break;
            case "CREDITO_PARCELADO_EMISSOR":
                flexTipoPagamento = FlexTipoPagamento.CREDITO_PARCELADO_EMISSOR;
                break;
            case "DEBITO":
                flexTipoPagamento = FlexTipoPagamento.DEBITO;
                break;
            case "VOUCHER":
                flexTipoPagamento = FlexTipoPagamento.VOUCHER;
                break;
            case "PIX":
                flexTipoPagamento = FlexTipoPagamento.PIX;
                break;
            default:
                flexTipoPagamento = FlexTipoPagamento.CREDITO_A_VISTA;
                break;
        }
        return flexTipoPagamento;
    }

}

class RedeL400PrinterManager {
    private final static String TAG = "RedeL400PrinterManager";
    public long totalLen = 0;
    public long currentLen = 0;

    public interface PrinterManagerListener {
        void onServiceConnected();
    }

    public RedeL400PrinterManager(Context context, PrinterManagerListener listener) {
        this.mContext = context;
        this.mListener = listener;
    }

    private final Context mContext;
    private final PrinterManagerListener mListener;

    private IPrinterCallback mCallback = null;
    private IPrinterService mPrinterService;

    private final ServiceConnection mConnectionService = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "Service Disconnected");
            mPrinterService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mPrinterService = IPrinterService.Stub.asInterface(service);
            mListener.onServiceConnected();
            Log.d(TAG, "Service Connected");
        }
    };

    public void onPrinterStart() {
        mCallback = new IPrinterCallback.Stub() {
            @Override
            public void onException(int code, final String msg) throws RemoteException {
                Log.w(TAG, "onException(" + code + "," + msg + ")");
            }

            @Override
            public void onLength(long current, long total) throws RemoteException {
                currentLen = current;
                totalLen = total;
            }

            public void onComplete() {

                Log.i(TAG, "onComplete()");
            }
        };

        Intent intent = new Intent();
        intent.setPackage("com.xcheng.printerservice");
        intent.setAction("com.xcheng.printerservice.IPrinterService");
        mContext.startService(intent);
        mContext.bindService(intent, mConnectionService, Context.BIND_AUTO_CREATE);
        Log.d("PrinterSample", "onPrinterStarted");
    }

    public void printText(final String text) {
        try {
            mPrinterService.printText(text, mCallback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void printBitmap(final Bitmap bitmap) {
        try {
            mPrinterService.printBitmap(bitmap, mCallback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void printerInit() {
        try {
            Log.d(TAG, "printerInit do PrintManager");
            mPrinterService.printerInit(mCallback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean printerPaper() {
        boolean hasPaper = false;
        try {
            hasPaper = mPrinterService.printerPaper(mCallback);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return hasPaper;
    }
}
