/*
 * Copyright (C) 2017 IOTA Foundation
 *
 * Authors: pinpong, adrianziser, saschan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.iota.wallet.ui.activity;

import android.Manifest;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v13.app.ActivityCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.iota.wallet.IOTA;
import org.iota.wallet.R;
import org.iota.wallet.api.TaskManager;
import org.iota.wallet.api.responses.error.NetworkError;
import org.iota.wallet.helper.Constants;
import org.iota.wallet.helper.RootDetector;
import org.iota.wallet.model.QRCode;
import org.iota.wallet.ui.dialog.RootDetectedDialog;
import org.iota.wallet.ui.fragment.AboutFragment;
import org.iota.wallet.ui.fragment.GenerateQRCodeFragment;
import org.iota.wallet.ui.fragment.NeighborsFragment;
import org.iota.wallet.ui.fragment.NewTransferFragment;
import org.iota.wallet.ui.fragment.NodeInfoFragment;
import org.iota.wallet.ui.fragment.PasswordLoginFragment;
import org.iota.wallet.ui.fragment.QRScannerFragment;
import org.iota.wallet.ui.fragment.SeedLoginFragment;
import org.iota.wallet.ui.fragment.SettingsFragment;
import org.iota.wallet.ui.fragment.TangleExplorerTabFragment;
import org.iota.wallet.ui.fragment.WalletAddressesFragment;
import org.iota.wallet.ui.fragment.WalletTabFragment;
import org.iota.wallet.ui.fragment.WalletTransfersFragment;

import java.util.Arrays;

import butterknife.BindView;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {

    private static final String STATE_CURRENT_FRAGMENT_TAG = "CURRENT_FRAGMENT_TAG";
    private static final String SHORTCUT_ID_GENERATE_QR_CODE = "generateQrCode";
    private static final String SHORTCUT_ID_SEND_TRANSFER = "sendTransfer";
    private static final int FRAGMENT_CONTAINER_ID = R.id.container;

    @BindView(R.id.drawer_layout)
    DrawerLayout drawer;
    @BindView(R.id.nav_view)
    NavigationView navigationView;

    private SharedPreferences prefs;
    private InputMethodManager inputManager;
    private String currentFragmentTag = null;
    private boolean killFragments = false;
    private OnBackPressedClickListener onBackPressedClickListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        navigationView.setNavigationItemSelectedListener(this);

        prefs = PreferenceManager.getDefaultSharedPreferences(this);
        inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

        if (savedInstanceState != null && savedInstanceState.containsKey(STATE_CURRENT_FRAGMENT_TAG)) {
                currentFragmentTag = savedInstanceState.getString(STATE_CURRENT_FRAGMENT_TAG);
        }

        if (savedInstanceState == null || IOTA.seed == null) {
            navigationView.getMenu().performIdentifierAction(R.id.nav_wallet, 0);
        }

        if (!prefs.getBoolean(Constants.PREFERENCE_RUN_WITH_ROOT, false)) {
            if (RootDetector.isDeviceRooted()) {
                RootDetectedDialog dialog = new RootDetectedDialog();
                dialog.show(this.getFragmentManager(), null);
            }
        }

        // shortcut intents
        if (savedInstanceState == null) {
            if (IOTA.seed != null) {
                if (Constants.ACTION_GENERATE_QR_CODE.equals(getIntent().getAction())) {
                    showFragment(new GenerateQRCodeFragment());
                } else if (Constants.ACTION_SEND_TRANSFER.equals(getIntent().getAction())) {
                    showFragment(new NewTransferFragment());
                }
            } else
                Snackbar.make(this.findViewById(R.id.drawer_layout), getString(R.string.messages_shortcuts_not_available), Snackbar.LENGTH_LONG);
        }


        drawer.addDrawerListener(drawerListener);
    }

    @Override
    public void setSupportActionBar(@Nullable Toolbar toolbar) {
        if (toolbar != null) {
            super.setSupportActionBar(toolbar);
            ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                    this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
            drawer.addDrawerListener(toggle);
            toggle.syncState();
        }
    }

    private DrawerLayout.DrawerListener drawerListener = new DrawerLayout.SimpleDrawerListener() {
        @Override
        public void onDrawerOpened(View drawerView) {
            super.onDrawerOpened(drawerView);
            inputManager.hideSoftInputFromWindow(drawerView.getWindowToken(), 0);
        }
    };


    @Override
    public void onBackPressed() {
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            if (onBackPressedClickListener != null)
                onBackPressedClickListener.onBackPressedClickListener();
            else if (getFragmentManager().getBackStackEntryCount() > 0)
                getFragmentManager().popBackStack();
            else
                super.onBackPressed();
        }
    }

    @Subscribe
    public void onEvent(NetworkError error) {
        String errorMessage = "";
        switch (error.getErrorType()) {
            case REMOTE_NODE_ERROR:
                errorMessage = getString(R.string.messages_network_remote_error);
                break;
            case NETWORK_ERROR:
                errorMessage = getString(R.string.messages_network_error);
                break;
            case ACCESS_ERROR:
                errorMessage = getString(R.string.messages_network_access_error);
                break;
            case INVALID_HASH_ERROR:
                errorMessage = getString(R.string.messages_invalid_hash_error);
                break;
            case EXCHANGE_RATE_ERROR:
                errorMessage = getString(R.string.messages_exchange_rate_error);
                break;
            case IOTA_COOL_NETWORK_ERROR:
                errorMessage = getString(R.string.messages_network_iota_cool_error);
                break;
        }

        Snackbar.make(findViewById(R.id.drawer_layout), errorMessage, Snackbar.LENGTH_LONG)
                .setAction(null, null).show();
    }

    /**
     * Shows a fragment and hides the old one if there was a fragment previously visible
     */
    private void showFragment(Fragment fragment, boolean addToBackStack, boolean killFragments) {

        if (fragment == null) {
            // Do nothing
            return;
        }

        FragmentManager fragmentManager = getFragmentManager();
        Fragment currentFragment = fragmentManager.findFragmentByTag(currentFragmentTag);

        if (currentFragment != null && currentFragment.getClass().getName().equals(fragment.getClass().getName())) {
            // Fragment already shown, do nothing
            return;
        }

        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();

        if (killFragments) {
            Class[] fragmentsToKill = {
                    AboutFragment.class,
                    GenerateQRCodeFragment.class,
                    NeighborsFragment.class,
                    NodeInfoFragment.class,
                    PasswordLoginFragment.class,
                    QRScannerFragment.class,
                    SeedLoginFragment.class,
                    SettingsFragment.class,
                    TangleExplorerTabFragment.class,
                    NewTransferFragment.class,
                    WalletAddressesFragment.class,
                    WalletTabFragment.class,
                    WalletTransfersFragment.class
            };
            for (Class fragmentClass : fragmentsToKill) {
                String tag = fragmentClass.getSimpleName();
                if (tag.equals(fragment.getClass().getSimpleName())) {
                    continue;
                }
                Fragment fragmentToKill = fragmentManager.findFragmentByTag(tag);
                if (fragmentToKill != null) {
                    fragmentTransaction.remove(fragmentToKill);
                }
            }
        }

        fragmentTransaction.setCustomAnimations(R.animator.fade_in, R.animator.fade_out,
                R.animator.fade_in, R.animator.fade_out);

        if (currentFragment != null) {
            // Hide old fragment
            fragmentTransaction.hide(currentFragment);
        }

        String tag = fragment.getClass().getSimpleName();
        Fragment cachedFragment = fragmentManager.findFragmentByTag(tag);
        if (cachedFragment != null) {
            // Cached fragment available
            fragmentTransaction.show(cachedFragment);
        } else {
            fragmentTransaction.add(FRAGMENT_CONTAINER_ID, fragment, tag);
        }
        if (addToBackStack) {
            fragmentTransaction.addToBackStack(null);
        }
        fragmentTransaction.commit();

        if (fragment instanceof OnBackPressedClickListener) {
            onBackPressedClickListener = (OnBackPressedClickListener) fragment;
        } else
            onBackPressedClickListener = null;

        // setChecked if open from WalletItemDialog
        if (fragment instanceof TangleExplorerTabFragment)
            navigationView.getMenu().findItem(R.id.nav_tangle_explorer).setChecked(true);

        currentFragmentTag = tag;
    }

    private void showFragment(Fragment fragment, boolean addToBackStack) {
        showFragment(fragment, addToBackStack, false);
    }

    public void showFragment(Fragment fragment) {
        showFragment(fragment, false);
    }

    private void showLogoutNavigationItem() {
        navigationView.getMenu().findItem(R.id.nav_logout).setVisible(IOTA.seed != null);
    }

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        Fragment fragment = null;
        getFragmentManager().popBackStack();

        switch (item.getItemId()) {
            case R.id.nav_wallet:
                String encSeed = prefs.getString(Constants.PREFERENCE_ENC_SEED, "");
                if (!encSeed.isEmpty() && IOTA.seed == null) {
                    showLogoutNavigationItem();
                    fragment = new PasswordLoginFragment();
                    killFragments = true;
                } else if (IOTA.seed == null) {
                    showLogoutNavigationItem();
                    fragment = new SeedLoginFragment();
                    killFragments = true;
                } else {
                    showLogoutNavigationItem();
                    fragment = getFragmentManager().findFragmentById(R.id.container);
                    if (fragment != null && fragment instanceof PasswordLoginFragment || fragment instanceof SeedLoginFragment)
                        killFragments = true;
                    fragment = new WalletTabFragment();
                }
                break;

            case R.id.nav_tangle_explorer:
                fragment = new TangleExplorerTabFragment();
                break;

            case R.id.nav_node_info:
                fragment = new NodeInfoFragment();
                break;

            case R.id.nav_neighbors:
                fragment = new NeighborsFragment();
                break;

            case R.id.nav_settings:
                Intent settings = new Intent(MainActivity.this, SettingsActivity.class);
                startActivity(settings);
                break;

            case R.id.nav_about:
                fragment = new AboutFragment();
                break;

            case R.id.nav_logout:
                AlertDialog alertDialog = new AlertDialog.Builder(this)
                        .setMessage(R.string.message_confirm_logout)
                        .setCancelable(false)
                        .setPositiveButton(R.string.buttons_ok, null)
                        .setNegativeButton(R.string.buttons_cancel, null)
                        .setNeutralButton(R.string.buttons_backup, null)
                        .create();

                alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.buttons_ok), (dialog, which) -> {
                            prefs.edit().remove(Constants.PREFERENCE_ENC_SEED).apply();
                            IOTA.seed = null;
                            TaskManager.stopAndDestroyAllTasks(MainActivity.this);
                            killFragments = true;
                            navigationView.getMenu().performIdentifierAction(R.id.nav_wallet, 0);
                        });

                alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, getString(R.string.buttons_backup), (dialog, which) -> {
                    Intent settings1 = new Intent(MainActivity.this, SettingsActivity.class);
                    startActivity(settings1);
                });

                alertDialog.show();

                break;
        }

        if (fragment != null) {
            showFragment(fragment, false, killFragments);
        }

        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    private void updateDynamicShortcuts() {
        ShortcutManager shortcutManager;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N_MR1) {

            Intent intentGenerateQrCode = new Intent(this, MainActivity.class);
            intentGenerateQrCode.setFlags((Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
            intentGenerateQrCode.setAction(Constants.ACTION_GENERATE_QR_CODE);

            ShortcutInfo shortcutGenerateQrCode = new ShortcutInfo.Builder(this, SHORTCUT_ID_GENERATE_QR_CODE)
                    .setShortLabel(getString(R.string.shortcut_generate_qr_code))
                    .setLongLabel(getString(R.string.shortcut_generate_qr_code))
                    .setIcon(Icon.createWithResource(this, R.drawable.ic_shortcut_qr))
                    .setIntent(intentGenerateQrCode)
                    .build();

            Intent intentTransferIotas = new Intent(this, MainActivity.class);
            intentTransferIotas.setFlags((Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
            intentTransferIotas.setAction(Constants.ACTION_SEND_TRANSFER);

            ShortcutInfo shortcutTransferIotas = new ShortcutInfo.Builder(this, SHORTCUT_ID_SEND_TRANSFER)
                    .setShortLabel(getString(R.string.shortcut_send_transfer))
                    .setLongLabel(getString(R.string.shortcut_send_transfer))
                    .setIcon(Icon.createWithResource(this, R.drawable.ic_shortcut_transaction))
                    .setIntent(intentTransferIotas)
                    .build();

            shortcutManager = getSystemService(ShortcutManager.class);

            if (shortcutManager != null) {
                if (IOTA.seed != null) {
                    shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutGenerateQrCode, shortcutTransferIotas));
                    shortcutManager.enableShortcuts(Arrays.asList(SHORTCUT_ID_GENERATE_QR_CODE, SHORTCUT_ID_SEND_TRANSFER));
                } else {
                    // remove shortcuts if Iota.seed.isEmpty()
                    shortcutManager.disableShortcuts(Arrays.asList(SHORTCUT_ID_GENERATE_QR_CODE, SHORTCUT_ID_SEND_TRANSFER));
                    shortcutManager.removeAllDynamicShortcuts();
                }
            }
        }
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
        switch (requestCode) {
            case Constants.REQUEST_CAMERA_PERMISSION:
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted!

                } else {

                    // permission denied!

                    if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
                            Manifest.permission.CAMERA)) {
                        Snackbar.make(findViewById(R.id.drawer_layout), R.string.messages_permission_camera,
                                Snackbar.LENGTH_LONG)
                                .setAction(R.string.buttons_ok, view -> {
                                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
                                    intent.addCategory(Intent.CATEGORY_DEFAULT);
                                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                    startActivityForResult(intent, Constants.REQUEST_CAMERA_PERMISSION);
                                })
                                .show();
                    }
                }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case Constants.REQUEST_CODE_LOGIN:
                inputManager.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
                navigationView.getMenu().performIdentifierAction(R.id.nav_wallet, 0);
        }
        if (data != null) {
            if (Intent.ACTION_VIEW.equals(data.getAction())) {
                QRCode qrCode = new QRCode();
                Uri uri = data.getData();
                qrCode.setAddress(uri.getQueryParameter("address:"));
                qrCode.setAddress(uri.getQueryParameter("amount:"));
                qrCode.setAddress(uri.getQueryParameter("message:"));

                Bundle bundle = new Bundle();
                bundle.putParcelable(Constants.QRCODE, qrCode);

                Fragment fragment = new NewTransferFragment();
                fragment.setArguments(bundle);
                showFragment(fragment, true);
            }
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        EventBus.getDefault().register(this);
        showLogoutNavigationItem();
        updateDynamicShortcuts();
    }

    @Override
    public void onPause() {
        super.onPause();
        updateDynamicShortcuts();
        EventBus.getDefault().unregister(this);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putString(STATE_CURRENT_FRAGMENT_TAG, currentFragmentTag);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        currentFragmentTag = savedInstanceState.getString(STATE_CURRENT_FRAGMENT_TAG);
    }

    @Override
    public void onDestroy() {
        drawer.removeDrawerListener(drawerListener);
        super.onDestroy();
    }

    public interface OnBackPressedClickListener {
        void onBackPressedClickListener();
    }
}