package com.getbubblenow.android.activity;

import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.security.KeyChain;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.airbnb.lottie.LottieAnimationView;
import com.getbubblenow.android.model.Network;
import com.getbubblenow.android.resource.StatusResource;
import com.getbubblenow.android.util.UserStore;
import com.getbubblenow.android.viewmodel.MainViewModel;
import com.getbubblenow.android.R;

public class MainActivity extends BaseActivityBubble {

    private MainViewModel mainViewModel;
    private TextView bubbleStatus;
    private TextView titleMyBubble;
    private Button connectButton;
    private ImageView imageMyBubble;
    private ImageView mark;
    private ImageButton accountButton;
    private ImageButton supportButton;
    private TextView logout;
    private boolean connectionStateFlag;

    private static final int REQUEST_CODE_VPN_PERMISSION = 23491;
    public static final int CONNECTED_TEXT_VIEW_LEFT_MARGIN = 16;
    public static final int CONNECTED_TEXT_VIEW_RIGHT_MARGIN = 16;
    public static final int CONNECTED_TEXT_VIEW_TOP_MARGIN = 150;
    public static final int DISCONNECTED_TEXT_VIEW_BOTTOM_MARGIN = 90;
    public static final int CONNECTED_TEXT_VIEW_BOTTOM_MARGIN = 100;
    private static final String BASE_URL_PREFIX = "https://";
    private static final String BASE_URL_SUFFIX_MY_BUBBLE = ":1443/appLogin?session=";
    private static final String BASE_URL_SUFFIX_ACCOUNT = "/appLogin?session=";
    private static final String URI_ACCOUNT = "&uri=/me";
    private static final String NO_INTERNET_CONNECTION = "no internet connection";
    private static final String LOGIN_FAILED = "Login Failed";
    private static final int REQUEST_CODE = 1555;
    private static final String CERTIFICATE_NAME = "Bubble Certificate";
    private String config = "";
    private  byte[] certificateEncode;
    private final String SUPPORT_URL = "https://support.getbubblenow.com";

    private ConstraintLayout constraint_layout_connected_title;
    private ConstraintLayout constraints_layout_connected_bubble;
    private ConstraintLayout constraint_layout_disconnected_title;
    private ConstraintLayout constraints_layout_disconnected_bubble;
    private ImageView union;
    private LottieAnimationView network_progress;
    private TextView progress_title;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainViewModel = new ViewModelProvider(this).get(MainViewModel.class);
        showLoadingDialog();
        if (mainViewModel.isHaveSageURL(this)) {
            if (mainViewModel.isHaveHostName(this)) {
                closeLoadingDialog();
                setContentView(R.layout.activity_main);
                mainViewModel.buildRepositoryInstance(this, mainViewModel.getSageURL(this));
                initUI();
                logout.setEnabled(true);
                connectButton.setEnabled(true);
            } else {
                setContentView(R.layout.activity_main);
                initUI();
                if (mainViewModel.checkRepositoryInstance()) {
                    mainViewModel.buildRepositoryInstance(this, mainViewModel.getSageURL(this));
                    getCertificateData();
                } else {
                    mainViewModel.buildClientService(mainViewModel.getSageURL(this));
                    getCertificateData();
                }
            }
        }
        else{
            closeLoadingDialog();
            Intent intent = new Intent(this, LoginActivity.class);
            startActivity(intent);
            finish();
        }
    }

    private void getCertificateData() {

        mainViewModel.getCertificateData(this).observe(this, new Observer<StatusResource<byte[]>>() {
            @Override public void onChanged(final StatusResource<byte[]> statusResource) {
                switch (statusResource.status) {
                    case SUCCESS:
                        certificateEncode = statusResource.data;
                        setConnectedBubbleUI();
                                mainViewModel.getConfig(MainActivity.this).observe(MainActivity.this, new Observer<StatusResource<String>>() {
                                    @Override public void onChanged(final StatusResource<String> stringStatusResource) {
                                        switch (stringStatusResource.status) {
                                            case SUCCESS:
                                                config = stringStatusResource.data;
                                                mainViewModel.setConfig(config,MainActivity.this);
                                                if (mainViewModel.isHaveCertificate(MainActivity.this)) {
                                                    createTunnel();
                                                } else {
                                                    final Intent intent = KeyChain.createInstallIntent();
                                                    intent.putExtra(KeyChain.EXTRA_CERTIFICATE, certificateEncode);
                                                    intent.putExtra(KeyChain.EXTRA_NAME, CERTIFICATE_NAME);
                                                    closeLoadingDialog();
                                                    startActivityForResult(intent, REQUEST_CODE);
                                                }
                                                break;
                                            case LOADING:
                                                break;
                                            case ERROR:
                                                closeLoadingDialog();
                                                if (stringStatusResource.message.equals(NO_INTERNET_CONNECTION)) {
                                                    showNetworkNotAvailableMessage();
                                                } else if (stringStatusResource.message.equals(LOGIN_FAILED)) {
                                                    Toast.makeText(MainActivity.this, LOGIN_FAILED, Toast.LENGTH_LONG).show();
                                                } else {
                                                    showErrorDialog(stringStatusResource.message);
                                                }
                                                break;
                                        }
                                    }
                                });
                        break;
                    case LOADING:
                        break;
                    case ERROR:
                        if (statusResource.message.equals(NO_INTERNET_CONNECTION)) {
                            showNetworkNotAvailableMessage();
                        } else if (statusResource.message.equals(LOGIN_FAILED)) {
                            Toast.makeText(MainActivity.this, LOGIN_FAILED, Toast.LENGTH_LONG).show();
                        } else {
                            showErrorDialog(statusResource.message);
                        }
                        break;
                }
            }
        });

        mainViewModel.getNetworkStatusLiveData().observe(this, new Observer<StatusResource<Network>>() {
            @Override public void onChanged(final StatusResource<Network> networkStatusResource) {
                if (!networkStatusResource.data.isRunning()) {
                    setProgressBubbleUI();
                    mainViewModel.getProgressLiveData().observe(MainActivity.this, new Observer<Long>() {
                        @Override public void onChanged(final Long percent) {
                            setProgress(percent);
                        }
                    });
                }
            }
        });
    }

    @Override protected void onResume() {
        super.onResume();
        if (mainViewModel.isHaveSageURL(this)) {
            if (mainViewModel.isHaveHostName(this)) {
                if (mainViewModel.isVPNConnected(this, connectionStateFlag)) {
                    connectionStateFlag = false;
                    setConnectionStateUI(false);
                } else {
                    connectionStateFlag = true;
                    setConnectionStateUI(true);
                }
            }
        }
    }

    private void initUI() {
        initViews();
        initListeners();
    }

    private void initViews() {
        bubbleStatus = findViewById(R.id.bubbleStatus);
        connectButton = findViewById(R.id.connectButton);
        imageMyBubble = findViewById(R.id.imageMyBubble);
        supportButton = findViewById(R.id.supportButton);
        mark = findViewById(R.id.mark);
        titleMyBubble = findViewById(R.id.titleMyBubble);
        accountButton = findViewById(R.id.accountButton);
        logout = findViewById(R.id.logout);
        constraint_layout_connected_title = findViewById(R.id.constraint_layout_connected_title);
        constraints_layout_connected_bubble = findViewById(R.id.constraints_layout_connected_bubble);
        constraint_layout_disconnected_title = findViewById(R.id.constraint_layout_disconnected_title);
        constraints_layout_disconnected_bubble = findViewById(R.id.constraints_layout_disconnected_bubble);
        union = findViewById(R.id.union);
        network_progress = findViewById(R.id.network_progress);
        progress_title = findViewById(R.id.progress_title);
    }

    private void initListeners() {
        connectButton.setOnClickListener(new OnClickListener() {
            @Override public void onClick(final View v) {
                connect();
            }
        });
        accountButton.setOnClickListener(new OnClickListener() {
            @Override public void onClick(final View v) {
                showAccount();
            }
        });
        logout.setOnClickListener(new OnClickListener() {
            @Override public void onClick(final View v) {
                logout();
            }
        });
        supportButton.setOnClickListener(new OnClickListener() {
            @Override public void onClick(final View v) {
                showSupport();
            }
        });
    }

    private void showAccount() {
        final String hostname = mainViewModel.getHostNameForAccount(this);
        if(!TextUtils.isEmpty(hostname)) {
            String token = mainViewModel.getToken(this);
            final String url = BASE_URL_PREFIX + hostname + BASE_URL_SUFFIX_MY_BUBBLE + token + URI_ACCOUNT;
            final Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setData(Uri.parse(url));
            startActivity(intent);
        }
        else {
            String sageToken = mainViewModel.getSageToken(this);
            final String sageHostname = mainViewModel.getSageHostname(this);
            final String url = sageHostname + BASE_URL_SUFFIX_ACCOUNT + sageToken + URI_ACCOUNT;
            final Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setData(Uri.parse(url));
            startActivity(intent);
        }
    }

    private void showSupport(){
        final Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(SUPPORT_URL));
        startActivity(intent);
    }

    private void connect() {
        if(mainViewModel.isHaveCertificate(this)) {
            mainViewModel.isHaveTunnel(this).observe(this, new Observer<StatusResource<Boolean>>() {
                @Override public void onChanged(final StatusResource<Boolean> booleanStatusResource) {
                    if(booleanStatusResource.data!=null){
                    if (booleanStatusResource.data) {
                        final boolean state = mainViewModel.isVPNConnected(MainActivity.this, connectionStateFlag);
                        connectionStateFlag = state;
                        mainViewModel.connect(state, MainActivity.this).observe(MainActivity.this, new Observer<Boolean>() {
                            @Override public void onChanged(final Boolean state) {
                                setConnectionStateUI(state);
                            }
                        });
                    } else {
                        createTunnel();
                        connect();
                    }
                }
                }
            });

        }
        else {
            final Intent intent = KeyChain.createInstallIntent();
            intent.putExtra(KeyChain.EXTRA_CERTIFICATE, certificateEncode);
            intent.putExtra(KeyChain.EXTRA_NAME, CERTIFICATE_NAME);
            startActivityForResult(intent, REQUEST_CODE);
        }
    }

    private void createTunnel(){
        showLoadingDialog();
        mainViewModel.createTunnel(this,UserStore.getInstance(this).getConfig()).observe(this, new Observer<StatusResource<Object>>() {
            @Override public void onChanged(final StatusResource<Object> objectStatusResource) {
                closeLoadingDialog();
                switch (objectStatusResource.status){
                    case SUCCESS:
                        closeLoadingDialog();
                        logout.setEnabled(true);
                        connectButton.setEnabled(true);
                        Toast.makeText(MainActivity.this, getString(R.string.success), Toast.LENGTH_SHORT).show();
                        Log.d("TAG", "Success");
                        break;
                    case LOADING:
                        break;
                    case ERROR:
                        closeLoadingDialog();
                        if(objectStatusResource.message.equals(NO_INTERNET_CONNECTION)){
                            showNetworkNotAvailableMessage();
                        }
                        else if(objectStatusResource.message.equals(LOGIN_FAILED)){
                            Toast.makeText(MainActivity.this,LOGIN_FAILED,Toast.LENGTH_LONG).show();
                        }
                        else {
                            showErrorDialog(objectStatusResource.message);
                        }
                        break;
                }
            }
        });
    }

    @Override protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_VPN_PERMISSION) {
            if (resultCode == RESULT_OK) {
                mainViewModel.connectWithPermission(connectionStateFlag, this)
                        .observe(this, new Observer<Boolean>() {
                            @Override public void onChanged(final Boolean state) {
                                setConnectionStateUI(state);
                            }
                        });
            } else {
                connectionStateFlag = false;
                setConnectionStateUI(false);
            }
        }
       else if (requestCode == REQUEST_CODE) {
             if(resultCode == RESULT_OK) {
                 createTunnel();
             }
             else {
                 logout.setEnabled(true);
                 connectButton.setEnabled(true);
                 Toast.makeText(this, getString(R.string.cerificate_install), Toast.LENGTH_LONG).show();
             }
        }
    }

    private void setConnectionStateUI(boolean state) {
        if (state) {
            bubbleStatus.setText(getString(R.string.connected_bubble));
            bubbleStatus.setTextColor(getResources().getColor(R.color.connectedColor));
            bubbleStatus.setPadding(CONNECTED_TEXT_VIEW_LEFT_MARGIN, CONNECTED_TEXT_VIEW_TOP_MARGIN, CONNECTED_TEXT_VIEW_RIGHT_MARGIN, DISCONNECTED_TEXT_VIEW_BOTTOM_MARGIN);
            connectButton.setText(getString(R.string.disconnect));
            imageMyBubble.setImageResource(R.drawable.bubble_connected);
            mark.setVisibility(View.VISIBLE);
            titleMyBubble.setVisibility(View.GONE);
        } else {
            bubbleStatus.setText(getString(R.string.not_connected_bubble));
            bubbleStatus.setTextColor(getResources().getColor(R.color.gray));
            bubbleStatus.setPadding(CONNECTED_TEXT_VIEW_LEFT_MARGIN, CONNECTED_TEXT_VIEW_TOP_MARGIN, CONNECTED_TEXT_VIEW_RIGHT_MARGIN, CONNECTED_TEXT_VIEW_BOTTOM_MARGIN);
            connectButton.setText(getString(R.string.connect));
            imageMyBubble.setImageResource(R.drawable.bubble_disconnected);
            mark.setVisibility(View.GONE);
            titleMyBubble.setVisibility(View.VISIBLE);
        }
    }

    private void logout() {
        final Intent intent = new Intent(this, LoginActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        mainViewModel.deleteTunnel(this);
        mainViewModel.removeSharedPreferences(this);
        startActivity(intent);
    }

    private void setConnectedBubbleUI() {
        union.setImageResource(R.drawable.union);
        constraint_layout_connected_title.setVisibility(View.VISIBLE);
        constraints_layout_connected_bubble.setVisibility(View.VISIBLE);
        constraint_layout_disconnected_title.setVisibility(View.GONE);
        constraints_layout_disconnected_bubble.setVisibility(View.GONE);
    }

    private void setProgressBubbleUI() {
        closeLoadingDialog();
        union.setImageResource(R.drawable.progress_background);
        constraint_layout_connected_title.setVisibility(View.GONE);
        constraints_layout_connected_bubble.setVisibility(View.GONE);
        constraint_layout_disconnected_title.setVisibility(View.VISIBLE);
        constraints_layout_disconnected_bubble.setVisibility(View.VISIBLE);
    }

    private void setProgress(long percent) {
        final long textProgress = percent;
        if (percent % 10 >= 5) {
            percent = percent + 10 - (percent % 10);
        } else {
            percent -= (percent % 10);
        }
        network_progress.setProgress(percent / 100f);
        progress_title.setText(textProgress + "%");
    }
}
