package kz.com.aman.kassa.handler;

import android.app.AlertDialog;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;

import com.google.gson.Gson;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import io.flutter.plugin.common.MethodChannel;
import kz.com.aman.kassa.bank.gui.CustomKeyBoardDilalog;
import kz.com.aman.kassa.model.AmanDao;
import kz.com.aman.kassa.plugins.BankNfcPlugins;
import ru.m4bank.mpos.library.external.transactions.CardPaymentCallbackHandler;
import ru.m4bank.mpos.service.commons.data.ResultType;
import ru.m4bank.mpos.service.data.FiscalStatusData;
import ru.m4bank.mpos.service.data.PrinterBaseData;
import ru.m4bank.mpos.service.data.PrinterErrorData;
import ru.m4bank.mpos.service.data.dynamic.objects.AdditionalTransactionData;
import ru.m4bank.mpos.service.data.dynamic.objects.GoodsData;
import ru.m4bank.mpos.service.data.dynamic.objects.Reader;
import ru.m4bank.mpos.service.data.dynamic.objects.Transaction;
import ru.m4bank.mpos.service.data.dynamic.objects.VendorData;
import ru.m4bank.mpos.service.data.dynamic.objects.printer.enums.AccountingSubject;
import ru.m4bank.mpos.service.data.dynamic.objects.printer.enums.TaxRate;
import ru.m4bank.mpos.service.data.dynamic.objects.result.ResultCode;
import ru.m4bank.mpos.service.hardware.error.AllError;
import ru.m4bank.mpos.service.hardware.error.ErrorHandler;
import ru.m4bank.mpos.service.hardware.external.cardreaderlib.data.ApplicationIdConv;
import ru.m4bank.mpos.service.hardware.external.cardreaderlib.data.enums.TransactionTypeConv;
import ru.m4bank.mpos.service.hardware.external.cardreaderlib.data.enums.VirtualKeyboardStyleTypeConv;
import ru.m4bank.mpos.service.result.PrinterResult;
import ru.m4bank.mpos.service.result.Result;
import ru.m4bank.mpos.service.transactions.data.ButtonKeyboardDto;
import ru.m4bank.mpos.service.transactions.data.MessageButtonData;
import ru.m4bank.mpos.service.transactions.data.TransactionData;
import ru.m4bank.mpos.service.transactions.data.TransactionExecutionStatus;
import ru.m4bank.mpos.service.transactions.data.VirtualPinKeyboardData;
import ru.m4bank.mpos.service.transactions.data.error.TransactionErrorData;
import ru.m4bank.mpos.service.transactions.dto.OnlineCardDataDto;
import timber.log.Timber;

public class CardPaymentHandlerImpl implements CardPaymentCallbackHandler<Result> {
    private final BankNfcPlugins plugin;
    private final MethodChannel.Result result;
    private final Long amount;
    private CustomKeyBoardDilalog customKeyBoardDilalog;
    private TransactionTypeConv transactionTypeConv;
    private final Gson gson = new Gson();

    public CardPaymentHandlerImpl(BankNfcPlugins plugin, MethodChannel.Result result, long amount, TransactionTypeConv type) {
        this.result = result;
        this.plugin = plugin;
        this.amount = amount;
        customKeyBoardDilalog = new CustomKeyBoardDilalog();
        transactionTypeConv = type;
    }

    public CardPaymentHandlerImpl setTransactionTypeConv(TransactionTypeConv transactionTypeConv) {
        this.transactionTypeConv = transactionTypeConv;
        return this;
    }

    @Override
    public void onDeviceToConnectSelectionRequested(List<String> deviceList) {
        System.out.println("----->---->---->onDeviceToConnectSelectionRequested");
        plugin.getActivity().runOnUiThread(() -> {
            AlertDialog.Builder builder = new AlertDialog.Builder(plugin.getActivity());
            builder.setTitle("Choose device");

            Spinner deviceListSpinner = new Spinner(plugin.getActivity());
            ArrayAdapter<String> adapter = new ArrayAdapter<>(plugin.getActivity(), android.R.layout.simple_spinner_item, deviceList);
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            deviceListSpinner.setAdapter(adapter);

            builder.setPositiveButton("OK", (dialog, which) -> {
                plugin.getClientInterface()
                        .getTransactionManager()
                        .selectCardReader(deviceListSpinner.getSelectedItem().toString());
                dialog.dismiss();
            });

            builder.setView(deviceListSpinner);
            builder.create().show();
        });
    }

    @Override
    public void onCardReaderForTransactionGettingCompleted() {
        System.out.println("----->---->---->Reader has been received");
    }

    @Override
    public void onNoBoundedDevicesFound() {
        System.out.println("----->---->---->No bounded readers");
    }

    @Override
    public void onDeviceToUseSelectionRequested(List<Reader> deviceList) {
        System.out.println("----->---->---->onDeviceToUseSelectionRequested");
        plugin.getActivity().runOnUiThread(() -> {
//            AlertDialog.Builder builder = new AlertDialog.Builder(plugin.getActivity());
//            builder.setTitle("Choose device");
//
//            Spinner deviceListSpinner = new Spinner(plugin.getActivity());
//            ArrayAdapter<Reader> adapter = new ArrayAdapter<>(plugin.getActivity(), android.R.layout.simple_spinner_item, new ArrayList<>(deviceList));
//            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//            deviceListSpinner.setAdapter(adapter);
//
//            builder.setPositiveButton("OK", (dialog, which) -> {
//                plugin.getClientInterface()
//                        .getTransactionManager()
//                        .setCardReaderToUse((Reader) deviceListSpinner.getSelectedItem());
//                dialog.dismiss();
//            });
//
//            builder.setView(deviceListSpinner);
//            builder.create().show();

            if (deviceList != null && !deviceList.isEmpty()) {
                for (Reader reader : deviceList) {
                    String name = reader.toString();
                    System.out.println("name: " + name);
                    if (name.contains("SOFT")) {
                        plugin.getClientInterface()
                                .getTransactionManager()
                                .setCardReaderToUse(reader);
                        break;
                    }
                }
            }
        });


    }

    @Override
    public void onTransactionAmountRequested() {
        System.out.println("----->---->---->onTransactionAmountRequested");
        plugin.getClientInterface().getTransactionManager().setTransactionAmount(this.amount);
    }

    @Override
    public void onTransactionDataRequested() {
        System.out.println("----->---->---->onTransactionDataRequested");
        List<GoodsData> goodsDataList = new ArrayList<>();
        goodsDataList.add(new GoodsData.Builder()
                .setOriginalPrice(100000L)
                .setRealPrice(100000L)
                .setName("Принтер")
                .setQuantity(1)
                .setCode("000001")
                .setUnits("00")
                .setDiscount(0L)
                .setTaxRate(TaxRate.Tax_18)
                .setExponent(2)
                .setAccountingSubject(AccountingSubject.PRODUCT)
                .build());
        goodsDataList.add(new GoodsData.Builder()
                .setOriginalPrice(30065L)
                .setRealPrice(30065L)
                .setName("Услуга")
                .setQuantity(3)
                .setCode("000002")
                .setUnits("00")
                .setDiscount(0L)
                .setTaxRate(TaxRate.Tax_18)
                .setExponent(2)
                .setAccountingSubject(AccountingSubject.PRODUCT)
                .build());

        HashMap<String, String> vendorDescription = new HashMap<>();
        vendorDescription.put("vendor", "description");
        vendorDescription.put("vendor1", "description1");
        vendorDescription.put("vendor2", "description2");
        vendorDescription.put("vendor3", "description3");
        VendorData vendorData = new VendorData(vendorDescription);

        AdditionalTransactionData additionalTransactionData = new AdditionalTransactionData.Builder(goodsDataList).vendorData(vendorData).build();
        plugin.getClientInterface().getTransactionManager().setAdditionalTransactionData(additionalTransactionData);
    }

    @Override
    public void onWorkFlowDataRequested() {
        System.out.println("----->---->---->WorkFlow requested");
    }

    @Override
    public void onCompleted(Result result) {
        System.out.println("----->---->---->onCompleted");
        plugin.getActivity().runOnUiThread(() -> Toast.makeText(plugin.getActivity(), result.getResultType() + " " + (result.getDescription() == null ? "" : result.getDescription()), Toast.LENGTH_SHORT)
                .show());
    }

    @Override
    public void onWrongApiCalled() {
        System.out.println("----->---->---->onWrongApiCalled");
        plugin.getActivity().runOnUiThread(() -> {
            //Toast.makeText(plugin.getActivity(), "Wrong method has been called", Toast.LENGTH_SHORT).show();
            AmanDao<String> dao = new AmanDao<>();
            dao.setSuccess(false);
            dao.setMsg("onWrongApiCalled");
            this.result.success(gson.toJson(dao));
        });
    }

    @Override
    public void onReceiveCardData(OnlineCardDataDto data, boolean shouldConfirmBeManuallyCalled) {
        System.out.println("----->---->---->onReceiveCardData");
        if (shouldConfirmBeManuallyCalled) {
            plugin.getClientInterface().getTransactionManager().processOnlineTransaction(false);
        }
    }

    @Override
    public void onTransactionInit() {
        //Impossible
        plugin.getClientInterface().getTransactionManager().processOnlineTransaction(false);
    }

    @Override
    public void onTransactionExecutionStatusChanged(TransactionExecutionStatus newStatus) {
        System.out.println("----->---->---->onTransactionExecutionStatusChanged: " + newStatus.name());
        plugin.getActivity().runOnUiThread(() ->  {
            if(newStatus!=null && newStatus.equals(TransactionExecutionStatus.TAP_CARD)) {
                Toast.makeText(plugin.getActivity(), newStatus.name(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public void onError(ErrorHandler errorHandler, TransactionErrorData transactionErrorData) {
        if (transactionErrorData.getError() != null) {
            plugin.getActivity().runOnUiThread(() -> Toast.makeText(plugin.getActivity(), transactionErrorData.getError().getDescription(), Toast.LENGTH_LONG).show());
        } else {
            plugin.getActivity().runOnUiThread(() -> {
                AmanDao<String> dao = new AmanDao<>();
                dao.setSuccess(false);
                dao.setMsg(String.format("%s", errorHandler.getFinalDescription()));
                this.result.success(gson.toJson(dao));
                //Toast.makeText(plugin.getActivity(), String.format("onError: %s, description: %s", ((AllError) errorHandler).name(), errorHandler.getFinalDescription()), Toast.LENGTH_LONG).show();
            });
        }
    }

    @Override
    public void onErrorWithPossibilityToRetry(ErrorHandler errorHandler) {
        System.out.printf("----->---->---->onErrorWithPossibilityToRetry: %s, description: %s", ((AllError) errorHandler).name(), errorHandler.getDescription());
        plugin.getActivity().runOnUiThread(() -> Toast.makeText(plugin.getActivity(), String.format("onError: %s, description: %s", ((AllError) errorHandler).name(), errorHandler.getFinalDescription()), Toast.LENGTH_LONG).show());
        plugin.getClientInterface().getTransactionManager().tryToRepeatExecuteLastRequestInTransaction();
    }

    @Override
    public void onTransactionDataReceivedError(TransactionData data) {
        System.out.println("----->---->---->onTransactionDataReceivedError");
    }

    @Override
    public void onUserInformationRequested(boolean signNeeded) {
        System.out.println("----->---->---->onUserInformationRequested");
        if (transactionTypeConv != TransactionTypeConv.CANCEL) {
            plugin.getClientInterface()
                    .getTransactionManager()
                    .sendTransactionUserData("signature", "phone", "vsa@centercorptech.net");
        } else {
            onTransactionCompleted();
        }
    }

    @Override
    public void onTransactionDataReceived(TransactionData data) {
        System.out.println("----->---->---->onTransactionDataReceived");

        plugin.getActivity().runOnUiThread(() -> {
            AmanDao<String> dao = new AmanDao<>();
            dao.setSuccess(true);
            dao.setMsg("OK");
            this.result.success(gson.toJson(dao));
            Toast.makeText(plugin.getActivity(), "Transaction data has been received", Toast.LENGTH_LONG)
                    .show();
        });
    }

    @Override
    public void onTransactionCompleted() {
        System.out.println("----->---->---->onTransactionCompleted");
        plugin.getActivity().runOnUiThread(() -> Toast.makeText(plugin.getActivity(), "Operation has been successfully completed", Toast.LENGTH_LONG)
                .show());
    }

    @Override
    public void onRequiredHostAddress() {
        System.out.println("----->---->---->onRequiredHostAddress");
        plugin.getActivity().runOnUiThread(() -> Toast.makeText(plugin.getActivity(), "Set Host Address", Toast.LENGTH_LONG)
                .show());
        plugin.getClientInterface().getTransactionManager().setHostAddress("213.79.122.128", "8011");
    }

    @Override
    public void onDisconnectedEventReceivedOrCanNotEstablishConnection(boolean reconnectAvailable, String description) {
        System.out.println("----->---->---->onDisconnectedEventReceivedOrCanNotEstablishConnection");
        if (reconnectAvailable) {
            plugin.getActivity().runOnUiThread(() -> {
                AlertDialog.Builder builder = new AlertDialog.Builder(plugin.getActivity());
                builder.setMessage("Connection to cardreader has been lost, try to reconnect and repeat last operation?");
                builder.setCancelable(false);
                builder.setPositiveButton("Yes", (dialog, which) -> plugin.getClientInterface().tryToReconnectAndRepeatLast());
                builder.setNegativeButton("No", (dialog, which) -> plugin.getClientInterface().cancel());
                builder.create().show();
            });
        }
    }

    @Override
    public void onConnectingProcessStarted(String deviceName) {
        System.out.printf("----->---->---->Connecting process started: %s\n", deviceName);
    }

    @Override
    public void onReconnectNeededToProcess() {
        System.out.println("----->---->---->onReconnectNeededToProcess");
        plugin.getActivity().runOnUiThread(() -> {
            AlertDialog.Builder builder = new AlertDialog.Builder(plugin.getActivity());
            builder.setMessage("Connection to cardreader has been lost, try to reconnect and continue?");
            builder.setCancelable(false);
            builder.setPositiveButton("Yes", (dialog, which) -> plugin.getClientInterface().getTransactionManager().tryToReconnectToCardReader());
            builder.setNegativeButton("No", (dialog, which) -> plugin.getClientInterface().cancel());
            builder.create().show();
        });
    }

    @Override
    public void onReconciliationRequiredToProcess() {
        System.out.println("----->---->---->onReconciliationRequiredToProcess");
        System.out.println("----->---->---->Reconciliation required!!!");
        plugin.getClientInterface().getTransactionManager().makeReconciliationDuringTransaction();
    }

    @Override
    public void onReconciliationCompleted(Result result) {
        System.out.println("----->---->---->onReconciliationCompleted");
        System.out.println("----->---->---->Reconciliation completed!!!");
        if (result.getResultType() == ResultType.SUCCESSFUL) {
            plugin.getClientInterface().getTransactionManager().continueTransactionAfterReconciliation();
        } else {
            plugin.getActivity().runOnUiThread(() -> Toast.makeText(plugin.getActivity(), "Reconciliation failed " + result.getDescription(), Toast.LENGTH_LONG)
                    .show());
        }
    }

    @Override
    public void notAuthorized() {
        System.out.println("----->---->---->notAuthorized");

        plugin.getActivity().runOnUiThread(() -> {
            AmanDao<String> dao = new AmanDao<>();
            dao.setSuccess(false);
            dao.setMsg("notAuthorized");
            this.result.success(gson.toJson(dao));
            Toast.makeText(plugin.getActivity(), "notAuthorized", Toast.LENGTH_SHORT).show();
        });
    }

    @Override
    public void onTransactionDetailsReceived(Transaction transaction) {
        System.out.println("----->---->---->onTransactionDetailsReceived");
        plugin.getActivity().runOnUiThread(() -> Toast.makeText(plugin.getActivity(), "Transaction details received", Toast.LENGTH_LONG)
                .show());
    }

    @Override
    public void onSuccessStatusTransaction(Transaction transaction) {
        System.out.println("----->---->---->onSuccessStatusTransaction");
    }

    @Override
    public void onErrorStatusTransaction() {
        System.out.println("----->---->---->onErrorStatusTransaction");
    }

    @Override
    public void onRepeat(int attemptNumber) {
        System.out.println("----->---->---->onRepeat");
        plugin.getActivity().runOnUiThread(() -> Toast.makeText(plugin.getActivity(), "Repeat attempt number " + attemptNumber, Toast.LENGTH_SHORT).show());
    }

    @Override
    public void onRequestedReportZ() {
        System.out.println("----->---->---->onRequestedReportZ");
    }

    @Override
    public void onCompletedPrinting(PrinterResult<PrinterErrorData, PrinterBaseData> printerErrorDataPrinterBaseDataPrinterResult) {
        System.out.println("----->---->---->onCompletedPrinting");
    }

    @Override
    public void onStatusFiscalModule(FiscalStatusData fiscalStatusData) {
        System.out.println("----->---->---->onStatusFiscalModule");
    }

    @Override
    public void onPrinterForRegistrationGettingCompleted() {
        System.out.println("----->---->---->onPrinterForRegistrationGettingCompleted");
    }

    @Override
    public void onNoBoundedPrinterFound() {
        System.out.println("----->---->---->onNoBoundedPrinterFound");

    }

    @Override
    public void onPrinterToUseSelectionRequested(List<String> printerList) {
        System.out.println("----->---->---->onPrinterToUseSelectionRequested");
    }

    @Override
    public void onRequiredReversal(String description, ResultCode resultCode) {
        System.out.printf("----->---->---->onRequiredReversal: %s, resultCode: %s\n", description, resultCode.name());
        plugin.getActivity().runOnUiThread(() -> {
            AlertDialog.Builder builder = new AlertDialog.Builder(plugin.getActivity());
            builder.setMessage("Revert last of operation?");
            builder.setCancelable(false);
            builder.setPositiveButton("Yes", (dialog, which) -> plugin.getClientInterface().getTransactionManager().revertCurrentOperation(new RevertCurrentOperationHandlerImpl(plugin)));
            builder.setNegativeButton("No", (dialog, which) -> plugin.getClientInterface().getTransactionManager().clearLastTransactionInformation());
            builder.create().show();
        });
    }

    @Override
    public void onRequiredApplicationSelection(List<ApplicationIdConv> list) {
        System.out.println("----->---->---->onRequiredApplicationSelection");
        plugin.getActivity().runOnUiThread(() -> {
            AlertDialog.Builder builder = new AlertDialog.Builder(plugin.getActivity());
            builder.setTitle("Choose application identifier");

            Spinner deviceListSpinner = new Spinner(plugin.getActivity());
            ArrayAdapter<ApplicationIdConv> adapter = new ArrayAdapter<>(plugin.getActivity(), android.R.layout.simple_spinner_item, list);
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            deviceListSpinner.setAdapter(adapter);

            builder.setPositiveButton("OK", (dialog, which) -> {
                plugin.getClientInterface()
                        .getTransactionManager()
                        .setTransactionApplicationIdentifier((ApplicationIdConv) deviceListSpinner.getSelectedItem());
                dialog.dismiss();
            });

            builder.setView(deviceListSpinner);
            builder.create().show();
        });
    }


    @Override
    public void onActivityUpdateUiThread() {
        System.out.println("----->---->---->onActivityUpdateUiThread");
        plugin.getClientInterface().getTransactionManager().addPinpadClickListener(plugin.getActivity());
    }


    @Override
    public void onCreatePinPadButtons() {
        System.out.println("----->---->---->onCreatePinPadButtons");
        customKeyBoardDilalog.createDialog(plugin.getActivity());
        customKeyBoardDilalog.show(plugin.getActivity());
        ButtonKeyboardDto buttonKeyboardDto = new ButtonKeyboardDto.Build(
                customKeyBoardDilalog.getBtnb1(),
                customKeyBoardDilalog.getBtnb2(),
                customKeyBoardDilalog.getBtnb3(),
                customKeyBoardDilalog.getBtnb4(),
                customKeyBoardDilalog.getBtnb5(),
                customKeyBoardDilalog.getBtnb6(),
                customKeyBoardDilalog.getBtnb7(),
                customKeyBoardDilalog.getBtnb8(),
                customKeyBoardDilalog.getBtnb9(),
                customKeyBoardDilalog.getBtnb0(),
                customKeyBoardDilalog.getBtncancel(),
                customKeyBoardDilalog.getBtnconfirm(),
                customKeyBoardDilalog.getBtnclean(),
                plugin.getActivity().getWindowManager().getDefaultDisplay().getRotation()
        ).build();
        plugin.getClientInterface().getTransactionManager().addPinPadButtons(buttonKeyboardDto);
    }

    @Override
    public void onShowPinPadKeyBoard(MessageButtonData messageButtonData) {
        System.out.println("----->---->---->onShowPinPadKeyBoard");
        customKeyBoardDilalog.setText(messageButtonData);
    }

    @Override
    public void onUpdateElementPin(int count) {
        System.out.println("----->---->---->onUpdateElementPin");
        plugin.getActivity().runOnUiThread(() -> Toast.makeText(plugin.getActivity(), "count = " + count, Toast.LENGTH_SHORT).show());
    }

    @Override
    public void onCloseKeyboard() {
        System.out.println("----->---->---->onCloseKeyboard");
        customKeyBoardDilalog.close(plugin.getActivity());
    }

    @Override
    public void onRequiredAdditionalVirtualKeyboardSettings(VirtualKeyboardStyleTypeConv virtualKeyboardStyleTypeConv) {
        //TODO FIX
//        plugin.getActivity().showSelectStyleDialog(additionalData ->
//                plugin.getClientInterface().getTransactionManager().addVirtualPinKeyboardData(additionalData));
    }

    public interface SelectStyleListener {
        void onSelectStyle(VirtualPinKeyboardData virtualPinKeyboardData);
    }
}
