package com.wallet.crypto.ui;

import android.app.Dialog;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import com.wallet.crypto.R;
import com.wallet.crypto.entity.ErrorEnvelope;
import com.wallet.crypto.entity.Wallet;
import com.wallet.crypto.ui.dialog.DialogManagerKt;
import com.wallet.crypto.ui.dialog.ExportWalletsDialog;
import com.wallet.crypto.ui.dialog.InputPwdDialog;
import com.wallet.crypto.ui.dialog.interfaces.IPositiveButtonDialogListener;
import com.wallet.crypto.ui.widget.adapter.WalletsAdapter;
import com.wallet.crypto.viewmodel.WalletsViewModel;
import com.wallet.crypto.viewmodel.WalletsViewModelFactory;
import com.wallet.crypto.widget.AddWalletView;
import com.wallet.crypto.widget.BackupWarningView;
import com.wallet.crypto.widget.SystemView;

import org.jetbrains.annotations.NotNull;

import javax.inject.Inject;

import static cn.magicwindow.core.config.Config.DIALOG_CREATE_PWD_REQUEST_CODE;
import static cn.magicwindow.core.config.Config.DIALOG_EXPORT_KEYSTORE_CODE;
import static cn.magicwindow.core.config.Config.DIALOG_EXPORT_PRIVATEKEY_CODE;
import static com.wallet.crypto.MercuryConstants.IMPORT_REQUEST_CODE;
import static com.wallet.crypto.MercuryConstants.SHARE_REQUEST_CODE;
import static com.wallet.crypto.ui.dialog.DialogManagerKt.showCusDialog;

public class WalletsActivity extends BaseActivity implements
        View.OnClickListener,
        IPositiveButtonDialogListener,
        AddWalletView.OnNewWalletClickListener,
        AddWalletView.OnImportWalletClickListener {

    @Inject
    WalletsViewModelFactory walletsViewModelFactory;
    WalletsViewModel viewModel;

    private WalletsAdapter adapter;

    private SystemView systemView;
    private BackupWarningView backupWarning;
    private Dialog dialog;
    private boolean isSetDefault;
    private Wallet wallet;
    private boolean exportPrivatekey;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
//		AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_wallets);
        // Init toolbar
        toolbar();

        adapter = new WalletsAdapter(this::onSetWalletDefault, this::onDeleteWallet, this::onExportWallet);
        SwipeRefreshLayout refreshLayout = findViewById(R.id.refresh_layout);
        systemView = findViewById(R.id.system_view);
        backupWarning = findViewById(R.id.backup_warning);

        RecyclerView list = findViewById(R.id.list);

        list.setLayoutManager(new LinearLayoutManager(this));
        list.setAdapter(adapter);

        systemView.attachRecyclerView(list);
        systemView.attachSwipeRefreshLayout(refreshLayout);
        backupWarning.setOnPositiveClickListener(this::onNowBackup);

        viewModel = ViewModelProviders.of(this, walletsViewModelFactory)
                .get(WalletsViewModel.class);

        viewModel.error().observe(this, this::onError);
        viewModel.progress().observe(this, systemView::showProgress);
        viewModel.wallets().observe(this, this::onFetchWallet);
        viewModel.defaultWallet().observe(this, this::onChangeDefaultWallet);
        viewModel.createdWallet().observe(this, this::onCreatedWallet);
        viewModel.exportedStore().observe(this, this::openShareDialog);

        refreshLayout.setOnRefreshListener(viewModel::fetchWallets);
    }

    private void onExportWallet(Wallet wallet) {
        this.wallet = wallet;
        DialogManagerKt.dialogBuilder(this, new ExportWalletsDialog())
                .setShowButtom(true)
                .setFullScreen(true)
                .setCancelableOnTouchOutside(false)
                .showAllowingStateLoss();
    }

    @Override
    protected void onPause() {
        super.onPause();
        hideDialog();
    }

    @Override
    public void onBackPressed() {
        // User can't start work without wallet.
        if (adapter.getItemCount() > 0) {
            viewModel.showTransactions(this);
        } else {
            finish();
            System.exit(0);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (adapter.getItemCount() > 0) {
            getMenuInflater().inflate(R.menu.menu_add, menu);
        }
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_add: {
                onAddWallet();
            }
            break;
            case android.R.id.home: {
                onBackPressed();
                return true;
            }
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == IMPORT_REQUEST_CODE) {
            showToolbar();
            if (resultCode == RESULT_OK) {
                viewModel.fetchWallets();
                Snackbar.make(systemView, getString(R.string.toast_message_wallet_imported), Snackbar.LENGTH_SHORT)
                        .show();
                if (adapter.getItemCount() <= 1) {
                    viewModel.showTransactions(this);
                }
            }
        } else if (requestCode == SHARE_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                Snackbar.make(systemView, getString(R.string.toast_message_wallet_exported), Snackbar.LENGTH_SHORT)
                        .show();
                backupWarning.hide();
                showToolbar();
                hideDialog();
                if (adapter.getItemCount() <= 1) {
                    onBackPressed();
                }
            } else {
                dialog = buildDialog()
                        .setMessage(R.string.do_manage_make_backup)
                        .setPositiveButton(R.string.yes_continue, (dialog, which) -> {
                            hideDialog();
                            backupWarning.hide();
                            showToolbar();
                            if (adapter.getItemCount() <= 1) {
                                onBackPressed();
                            }
                        })
                        .setNegativeButton(R.string.no_repeat,
                                (dialog, which) -> {
                                    openShareDialog(viewModel.exportedStore().getValue());
                                    hideDialog();
                                })
                        .create();
                dialog.show();
            }
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.try_again: {
                viewModel.fetchWallets();
            }
            break;
        }
    }

    /**
     * 创建钱包
     *
     * @param view
     */
    @Override
    public void onNewWallet(View view) {
        showInputPwdDialog(false);
        hideDialog();
    }

    /**
     * 导入钱包
     *
     * @param view
     */
    @Override
    public void onImportWallet(View view) {
        hideDialog();
        viewModel.importWallet(this);
    }

    private void onAddWallet() {
        AddWalletView addWalletView = new AddWalletView(this);
        addWalletView.setOnNewWalletClickListener(this);
        addWalletView.setOnImportWalletClickListener(this);
        dialog = new BottomSheetDialog(this);
        dialog.setContentView(addWalletView);
        dialog.setCancelable(true);
        dialog.setCanceledOnTouchOutside(true);
        dialog.show();
    }

    private void onChangeDefaultWallet(Wallet wallet) {
        if (isSetDefault) {
            viewModel.showTransactions(this);
        } else {
            adapter.setDefaultWallet(wallet);
        }
    }

    private void onFetchWallet(Wallet[] wallets) {
        if (wallets == null || wallets.length == 0) {
            dissableDisplayHomeAsUp();
            AddWalletView addWalletView = new AddWalletView(this, R.layout.layout_empty_add_account);
            addWalletView.setOnNewWalletClickListener(this);
            addWalletView.setOnImportWalletClickListener(this);
            systemView.showEmpty(addWalletView);
            adapter.setWallets(new Wallet[0]);
            hideToolbar();
        } else {
            enableDisplayHomeAsUp();
            adapter.setWallets(wallets);
        }
        invalidateOptionsMenu();
    }

    private void onCreatedWallet(Wallet wallet) {
        hideToolbar();
        backupWarning.show(wallet);
    }

    private void onLaterBackup(View view, Wallet wallet) {
        showNoBackupWarning(wallet);
    }

    private void onNowBackup(View view, Wallet wallet) {
        if (exportPrivatekey) {
            showInputPwdDialog(true);
        } else {
            viewModel.exportWallet(wallet);
        }
    }

    private void showNoBackupWarning(Wallet wallet) {
        dialog = buildDialog()
                .setTitle(getString(R.string.title_dialog_watch_out))
                .setMessage(getString(R.string.dialog_message_unrecoverable_message))
                .setIcon(R.drawable.ic_warning_black_24dp)
                .setPositiveButton(R.string.i_understand, (dialog, whichButton) -> {
                    backupWarning.hide();
                    showToolbar();
                })
                .setNegativeButton(android.R.string.cancel, null) //(dialog, whichButton) -> showBackupDialog(wallet, true)
                .create();
        dialog.show();
    }

    private void openShareDialog(String jsonData) {
        Intent sharingIntent = new Intent(Intent.ACTION_SEND);
        sharingIntent.setType("text/plain");
        sharingIntent.putExtra(Intent.EXTRA_SUBJECT, "Keystore");
        sharingIntent.putExtra(Intent.EXTRA_TEXT, jsonData);
        startActivityForResult(
                Intent.createChooser(sharingIntent, "Share via"),
                SHARE_REQUEST_CODE);
    }

    private void onError(ErrorEnvelope errorEnvelope) {
        systemView.showError(errorEnvelope.message, this);
    }

    private void onSetWalletDefault(Wallet wallet) {
        viewModel.setDefaultWallet(wallet);
        isSetDefault = true;
    }

    private void onDeleteWallet(Wallet wallet) {
        dialog = buildDialog()
                .setTitle(getString(R.string.title_delete_account))
                .setMessage(getString(R.string.confirm_delete_account))
                .setIcon(R.drawable.ic_warning_black_24dp)
                .setPositiveButton(android.R.string.yes, (dialog, btn) -> viewModel.deleteWallet(wallet))
                .setNegativeButton(android.R.string.no, null)
                .create();
        dialog.show();
    }

    private AlertDialog.Builder buildDialog() {
        hideDialog();
        return new AlertDialog.Builder(this);
    }

    private void hideDialog() {
        if (dialog != null && dialog.isShowing()) {
            dialog.dismiss();
            dialog = null;
        }
    }

    @Override
    public void onPositiveButtonClicked(int requestCode, @NotNull Object any) {
        switch (requestCode) {
            case DIALOG_EXPORT_PRIVATEKEY_CODE:
                showInputPwdDialog(true);
                break;
            case DIALOG_EXPORT_KEYSTORE_CODE:
                viewModel.exportWallet(wallet);
                break;
            case DIALOG_CREATE_PWD_REQUEST_CODE:
                if (exportPrivatekey) {
                    viewModel.exportPrivateKey((String) any, wallet);
                } else {
                    viewModel.newWallet((String) any);
                }
                break;
        }
    }

    private void showInputPwdDialog(boolean exportPrivatekey) {
        this.exportPrivatekey = exportPrivatekey;
        showCusDialog(this, new InputPwdDialog());
    }
}