package id.mdd.implementationpartnerconnect;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.media.MediaPlayer;
import android.nfc.NfcAdapter;
import android.nfc.NfcManager;
import android.nfc.Tag;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.mdd.topupUnik.ubal.ApiUtils;
import com.mdd.topupUnik.ubal.InitDebugCertificate;
import com.mdd.topupUnik.ubal.InitReader;
import com.mdd.topupUnik.ubal.MainCardProcessor;
import com.mdd.topupUnik.ubal.SuccessUpdateBalance;
import com.mdd.topupUnik.ubal.UpdateBalanceView;
import com.mdd.topupUnik.ubal.http.response.CardBalanceAPDUResponse;
import com.mdd.topupUnik.ubal.lib.CardInfo;
import com.mdd.topupUnik.ubal.lib.CardInfoCommand;
import com.mdd.topupUnik.ubal.lib.CommandResult;
import com.medicom.dudikov.mybanklibrary.nativeLib;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;

import butterknife.BindView;
import butterknife.ButterKnife;
import id.emhusnan.mdd.service.ConfigService;
import id.emhusnan.mdd.service.LibraryConfig;
import id.emhusnan.mdd.service.MDDUpdateBalanceView;

import static com.medicom.organicdrv.utilsLib.ByteArrayToHexString;

public class NewMainActivity extends AppCompatActivity implements MDDUpdateBalanceView, InitListener, NfcAdapter.ReaderCallback {

    private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 1;
    private static final String TAG = "NewMainActivity";
    @BindView(R.id.logoCard)
    ImageView logoCard;
    @BindView(R.id.textCardBalance)
    TextView textCardBalance;
    @BindView(R.id.textCardNumber)
    TextView textCardNumber;
    @BindView(R.id.btnGantiKartu)
    ImageButton btnGantiKartu;
    @BindView(R.id.bgCard)
    LinearLayout bgCard;
    @BindView(R.id.pgProcess)
    ProgressBar pgProcess;
    @BindView(R.id.txtStatus)
    TextView txtStatus;
    @BindView(R.id.btnUpdateBalance)
    Button btnUpdateBalance;
    @BindView(R.id.txtAmount)
    TextView txtAmount;
    @BindView(R.id.textCardBalanceNew)
    TextView textCardBalanceNew;
    @BindView(R.id.lyUpdateBalance)
    LinearLayout lyUpdateBalance;
    @BindView(R.id.btnAktivasiAar)
    Button btnAktivasiAar;
    @BindView(R.id.about)
    TextView about;
    @BindView(R.id.version)
    TextView version;
    @BindView(R.id.pbloading)
    ProgressBar pbloading;
    DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);
    private int idDriver = nativeLib.USE_SunMi_ENGGINE;
    private InitReader reader;
    private MainCardProcessor cardProcessor;
    private boolean hasPendingOperation;
    private int oldBalance = 0;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        validateHasPermissions();
    }

    private void validateHasPermissions() {
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);

        // permission READ_PHONE_STATE
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "Please grant permission", Toast.LENGTH_SHORT).show();
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.READ_PHONE_STATE)) {
            } else {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.READ_PHONE_STATE,
                                Manifest.permission.INTERNET,
                                Manifest.permission.READ_EXTERNAL_STORAGE},
                        MY_PERMISSIONS_REQUEST_READ_CONTACTS);
            }

        } else {
            Log.d("Init", "--> Init");
//            ((MyApp) getApplication()).initAar(this);
            ConfigService configService = new ConfigService();
            configService.setMid("1234567abc");
            configService.setToken("165eea86947a4e9483d1902f93495fc6");
            String accessToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhdXRoLXNlcnZpY2U6MS4wLjAiLCJzdWIiOnsibmFtZSI6IlRlc3RTdGFnIiwidXNlcm5hbWUiOiJUZXN0U3RhZyIsImF1dGhfbGV2ZWwiOiJNRVJDSEFOVCIsIm1pZCI6IjIwZjFmMTNmODA1MGFjY2QxYjNjNzFlOWUyYTQ0NzU3In0sImlhdCI6MTU5MzQxMzM5MCwiZXhwIjoxNzUxMTk4MTUwLCJuYmYiOjE1OTM0MTMzOTJ9.E6UJMKha5YCbri4KRExDV4zeA1ZBfabpW-O6SInxxvfyTTYnUZCEu58STBGrOCL0RuxTFp5Y-XEyoa932fQcTpMBMsKkvDmGeftJ0hmjzAxAjHTfUxUyEa-HHF1whsM4YQUG9CesEBjU9IUcE6Rs-jykYxuryvvqqop5BoEIwO71qQBrq6DtpwjwFk9hbNt0EKs_HmCpySfXQxorfLMbAVJCHBYoo4UVymUfwUbps7hW6eQwNoBnt11O59CRPf6uUVIfCrsaaBMcJI-mc214-EMyl3RmMbqNl_f_0ITEJhMtK2zbUFZ8dMrGdZZgWJxiHdmzxqdaEPDVshYi9Uo31w";

            LibraryConfig mConfig = new LibraryConfig(
                    configService.getMid(),
                    Settings.Secure.ANDROID_ID,
                    configService.getToken(),
                    accessToken,
                    ApiUtils.dev_environment
            );

            final nativeLib[] nativeLibrary = new nativeLib[1];
            InitDebugCertificate initDebugCertificate = new InitDebugCertificate();
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        nativeLibrary[0] = new nativeLib(getApplicationContext(), idDriver);
                        reader = initDebugCertificate.getDebug(nativeLibrary[0], getApplicationContext(), idDriver, mConfig, true);
//                        Log.e("reader", new Gson().toJson(reader));
                        pbloading.setVisibility(View.GONE);
                        execute(null);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    @Override
    public void onTagDiscovered(Tag tag) {
        execute(tag);
    }

    @Override
    public void onNFcCardNotSupported(int i) {
        hasPendingOperation = false;
        Toast.makeText(this, R.string.nfc_not_found, Toast.LENGTH_SHORT).show();
        NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE);
        NfcAdapter adapter = manager.getDefaultAdapter();
        Log.d(TAG, "adapter:" + adapter + "," + Build.MODEL + "," + Build.BRAND);

        if (adapter == null || !adapter.isEnabled()) {
            txtStatus.setTextColor(getResources().getColor(R.color.text_error));
            txtStatus.setText(R.string.nfc_not_found);
        }
//        showProgressBar();
        displayResult(R.color.text_normal, R.string.nfc_not_found);
        findViewById(R.id.lyUpdateBalance).setVisibility(View.GONE);
    }

    @Override
    public void onNfcCardFound() {
        hasPendingOperation = true;
        Toast.makeText(this, "Mohon Tunggu...", Toast.LENGTH_LONG).show();
//        showProgressBar();
        displayResult(R.color.text_normal, R.string.keep_tap);
        findViewById(R.id.lyUpdateBalance).setVisibility(View.GONE);
    }

    @Override
    public void onFinishOperation() {
        hasPendingOperation = false;
        Toast.makeText(this, "On Finishoperation", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onBalanceInfoAvailable(CardInfo cardInfo) {
        hasPendingOperation = false;
        Log.d(TAG, "onBalanceInfoAvailable: " + cardInfo.getBalance());

        runOnUiThread(() -> {
//            pgProcess.setVisibility(View.VISIBLE);
            if (cardInfo.getBankType().equals("BNI")) {
                bgCard.getBackground().setColorFilter(Color.parseColor("#F6630E"), PorterDuff.Mode.SRC_ATOP);
                logoCard.setImageResource(R.drawable.tapcash_logo);
            } else {
                bgCard.getBackground().setColorFilter(Color.parseColor("#013C76"), PorterDuff.Mode.SRC_ATOP);
                logoCard.setImageResource(R.drawable.logo_emoney);

            }
            oldBalance = cardInfo.getBalance();
            txtAmount.setText("Rp " + cardInfo.getBalance());
            textCardNumber.setText(cardInfo.getCardNumber());
            txtStatus.setTextColor(getColorRes(R.color.text_normal));

        });
        beep();
    }

    private void beep() {
        MediaPlayer mp = MediaPlayer.create(this, R.raw.beep);
        mp.start();
    }

    @Override
    public void onUpdateBalaceSuccess(SuccessUpdateBalance successUpdateBalance) {

    }

    @Override
    public void onUpdateBalanceError(String s) {

    }

    @Override
    public void onBeginOperation() {
        hasPendingOperation = true;
        Toast.makeText(this, "Begin Transaction", Toast.LENGTH_SHORT).show();
        Log.d(TAG, "onBeginOperation: ");
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        displayResult(R.color.text_normal, R.string.keep_tap);
//        showProgressBar();
        findViewById(R.id.lyUpdateBalance).setVisibility(View.GONE);
    }

    @Override
    public void onInitReaderComplete(InitReader reader) {

    }

    private void displayResult(int p, int p2) {
        txtStatus.setTextColor(getColorRes(p));
        txtStatus.setText(p2);
    }

    private int getColorRes(int res) {
        if (Build.VERSION.SDK_INT < 23) {
            return getResources().getColor(res);
        }
        return getColor(res);
    }

//    private void showProgressBar() {
//        pgProcess.setVisibility(View.VISIBLE);
//    }

    private void execute(Tag tag) {
        Log.d("Execute", "--> execute");
        if (reader != null) {
            cardProcessor = new MainCardProcessor(this, reader, new UpdateBalanceView() {
                @Override
                public void onUpdateBalanceSuccess(SuccessUpdateBalance successUpdateBalance) {
                    runOnUiThread(() -> onUpdateBalaceSuccess(successUpdateBalance));
                }

                @Override
                public void onUpdateBalanceError(String reason) {
                    runOnUiThread(() -> onUpdateBalanceError(reason));
                }

                @Override
                public void onCardDetected(CardInfo cardInfo) {
                    runOnUiThread(() -> onBalanceInfoAvailable(cardInfo));
                }

                @Override
                public void onErrorNfcCardMsg(int errorCode) {
                    runOnUiThread(() -> onUpdateBalanceError(""));
                }
            }, ApiUtils.dev_environment);
            if (tag != null) {
                cardProcessor.lockIsoDepCard(tag);
                String cardUid = ByteArrayToHexString(tag.getId());
                Log.d("TagFromIntent", cardUid);
                boolean hasCardUid = !cardUid.isEmpty();
                if (hasCardUid) {
                    Log.d(TAG, "---> Send to UI Card Found");
                    runOnUiThread(this::onNfcCardFound);

                    CardInfoCommand command = new CardInfoCommand(reader.myReader);
                    Log.e("myReader", "Myreader : " + reader.myReader);

                    final CommandResult<CardInfo> execute = command.execute(cardUid);
                    CardInfo detectedCardInfo = execute.getResult();
                    Log.d("executeSuccess", "executeIsSuccess = " + execute.isSuccess());
                    if (execute.isSuccess()) {
                        if (detectedCardInfo.getBankType().toLowerCase().contains("dki")
                                || detectedCardInfo.getBankType().toLowerCase().contains("bca")) {
                            runOnUiThread(() -> {
                                onBalanceInfoAvailable(detectedCardInfo);
                                pgProcess.setVisibility(View.GONE);
                                txtStatus.setText(R.string.tap_card);
                            });
                        } else {
//                            cardProcessor.getBalance(detectedCardInfo, null);
                            cardProcessor.updateBalance(detectedCardInfo, 1, null);
                        }
                    } else {
                        runOnUiThread(() -> {
                            Log.e("error", "Messagenya : " + execute.getMessage());
                            onUpdateBalanceError("Kartu tidak terdeteksi");
                            cardProcessor.unlockIsoDepCard();
                        });
                    }
                    cardProcessor.unlockIsoDepCard();

                } else {
                    //wrong card type
                    cardProcessor.unlockIsoDepCard();
                }
            } else {
                CardInfoCommand command = new CardInfoCommand(reader.myReader);
                Log.e("myReader", "Myreader : " + reader.myReader);
                String cardUID = cardProcessor.findCardUid();

                final CommandResult<CardInfo> execute = command.execute(cardUID);
                CardInfo detectedCardInfo = execute.getResult();
                Log.d("executeSuccess", "executeIsSuccess = " + execute.isSuccess());
                if (execute.isSuccess()) {
                    if (detectedCardInfo.getBankType().toLowerCase().contains("dki")
                            || detectedCardInfo.getBankType().toLowerCase().contains("bca")) {
                        runOnUiThread(() -> {
                            onBalanceInfoAvailable(detectedCardInfo);
                            pgProcess.setVisibility(View.GONE);
                            txtStatus.setText(R.string.tap_card);
                        });
                    } else {
//                        cardProcessor.getBalance(detectedCardInfo, null);
                        cardProcessor.updateBalance(detectedCardInfo, 1, null);
                    }
                } else {
                    CardBalanceAPDUResponse cardBalanceAPDUResponse = cardProcessor.getBalance();
                    CardInfo cardInfo = new CardInfo(cardBalanceAPDUResponse.getBalance(), cardBalanceAPDUResponse.getCardNumber(), "Mandiri", cardBalanceAPDUResponse.getCardUid());
                    onBalanceInfoAvailable(cardInfo);
                }
            }
        }
    }
}
