package co.pixelbeard.theanfieldwrap.accountDetails;


import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.rw.keyboardlistener.KeyboardUtils;

import br.com.simplepass.loadingbutton.customViews.CircularProgressButton;
import butterknife.BindView;
import butterknife.ButterKnife;
import co.pixelbeard.theanfieldwrap.R;
import co.pixelbeard.theanfieldwrap.customView.PBInputField;
import co.pixelbeard.theanfieldwrap.data.source.DataRepository;
import co.pixelbeard.theanfieldwrap.data.source.local.LocalRepository;
import co.pixelbeard.theanfieldwrap.data.source.remote.RemoteRepository;
import co.pixelbeard.theanfieldwrap.dialog.twoButton.TwoButtonDialogListener;
import co.pixelbeard.theanfieldwrap.home.HomeActivity;
import co.pixelbeard.theanfieldwrap.home.HomeFragmentListener;
import co.pixelbeard.theanfieldwrap.playerService.MediaPlayerInterface;
import co.pixelbeard.theanfieldwrap.playerService.PodcastStorageUtil;
import co.pixelbeard.theanfieldwrap.utils.BaseFragment;
import co.pixelbeard.theanfieldwrap.utils.ConnectionUtils;
import co.pixelbeard.theanfieldwrap.utils.DialogUtils;
import co.pixelbeard.theanfieldwrap.utils.FontUtils;
import co.pixelbeard.theanfieldwrap.utils.OnBackPressedOverrideListener;
import co.pixelbeard.theanfieldwrap.utils.PrefKey;
import co.pixelbeard.theanfieldwrap.utils.PrefUtils;
import co.pixelbeard.theanfieldwrap.utils.TawController;
import co.pixelbeard.theanfieldwrap.utils.ValidationUtils;
import io.realm.Realm;

public class AccountDetailsFragment extends BaseFragment implements AccountDetailsContract.View {

    private static final String TAG = AccountDetailsFragment.class.getSimpleName();

    @BindView(R.id.ll_back)
    LinearLayout llBack;

    @BindView(R.id.pb_edit_first_name)
    PBInputField pbEditFirstName;
    @BindView(R.id.pb_edit_last_name)
    PBInputField pbEditLastName;
    @BindView(R.id.pb_edit_user_name)
    PBInputField pbEditUserName;


    @BindView(R.id.txt_account_details_title)
    TextView txtAccountDetailsTitle;

    @BindView(R.id.txt_edit_email)
    TextView txtEditEmail;
    @BindView(R.id.txt_edit_password)
    TextView txtEditPassword;
    @BindView(R.id.ll_edit_email)
    LinearLayout llEditEmail;
    @BindView(R.id.ll_edit_password)
    LinearLayout llEditPassword;

    @BindView(R.id.input_stopper)
    View inputStopper;

    @BindView(R.id.btn_save)
    CircularProgressButton btnSave;

    private boolean userNameAvailable;


    private Context mContext;
    private HomeFragmentListener mListener;
    private MediaPlayerInterface mediaPlayerInterface;

    private ConnectivityManager cm;
    private ConnectivityManager.NetworkCallback networkCallback;

    private AccountDetailsContract.Presenter mPresenter;

    public AccountDetailsFragment() {
        // Required empty public constructor
    }

    public static AccountDetailsFragment newInstance() {
        AccountDetailsFragment fragment = new AccountDetailsFragment();
        Bundle args = new Bundle();

        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        mContext = context;
        mListener = (HomeFragmentListener) context;
        mediaPlayerInterface = (MediaPlayerInterface) context;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {

        }
        new AccountDetailsPresenter(this, new DataRepository(new LocalRepository(Realm.getDefaultInstance()), new RemoteRepository()));
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_account_details, container, false);
        ButterKnife.bind(this, view);
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        setTextViewFonts();
        setButtonFont();
        setClickListeners();

        setInputFieldFont();
        setInputFieldImeListener();
    }

    @Override
    public void onStart() {
        super.onStart();


        if (mContext != null) {
            cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
        }

        NetworkRequest networkRequest = new NetworkRequest.Builder().build();
        networkCallback = new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(Network network) {
                super.onAvailable(network);
                checkForDetails();
            }

            @Override
            public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
                super.onLinkPropertiesChanged(network, linkProperties);
                checkForDetails();
            }

            @Override
            public void onLost(Network network) {
                super.onLost(network);
                checkForDetails();
            }

            @Override
            public void onCapabilitiesChanged(Network network, NetworkCapabilities
                    networkCapabilities) {
                super.onCapabilitiesChanged(network, networkCapabilities);
                checkForDetails();
            }

            @Override
            public void onUnavailable() {
                super.onUnavailable();
                checkForDetails();
            }

            @Override
            public void onLosing(Network network, int maxMsToLive) {
                super.onLosing(network, maxMsToLive);
                checkForDetails();
            }
        };

        if (cm != null) {
            cm.registerNetworkCallback(networkRequest, networkCallback);
        }
    }


    @Override
    public void onStop() {
        super.onStop();
        try {
            cm.unregisterNetworkCallback(networkCallback);
        } catch (Exception e) {
            Log.d("NETWORK CALLBACK", "NetworkCallback for Wi-fi was not registered or already unregistered");
        }

    }

    @Override
    public void onResume() {
        super.onResume();
        TawController.setCurrentPage(TAG);

        if (isAdded() && !isDetached()) {
            setData();
            setInputFieldTextWatcher();
        }

        new Handler().postDelayed(() -> llBack.setOnClickListener(v -> {
            llBack.setEnabled(false);
            mListener.goBack();
        }), 500);

        checkForDetails();
    }


    private void checkForDetails() {
        if (isAdded()) {
            ((HomeActivity) mContext).runOnUiThread(() -> {
                if (checkConnection()) {
                    enableEdits();
                } else {
                    disableEdits();
                    onConnectionError();
                }
            });
        }
    }


    private void setTextViewFonts() {
        txtAccountDetailsTitle.setTypeface(FontUtils.getInstance().getDinProBlack());

        txtEditEmail.setTypeface(FontUtils.getInstance().getDinAlternateBold());
        txtEditPassword.setTypeface(FontUtils.getInstance().getDinAlternateBold());
    }

    private void setButtonFont() {
        btnSave.setTypeface(FontUtils.getInstance().getDinAlternateBold());
    }

    private void setClickListeners() {

        llEditEmail.setOnClickListener(v -> {
            mListener.setEditEmailFrag();
        });

        llEditPassword.setOnClickListener(v -> {
            mListener.setEditPasswordFrag();
        });

        inputStopper.setOnClickListener(v -> {
            onConnectionError();
        });

        btnSave.setOnClickListener(v -> {
            if (mPresenter.checkForChanges(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText())) {
                if (mPresenter.validateFields(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText(), false)) {
                    mPresenter.updateUserDetails(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText());
                }
            } else {
                mListener.goBack();
            }
        });
    }

    private void setInputFieldFont() {
        pbEditFirstName.setInputType(InputType.TYPE_TEXT_FLAG_CAP_WORDS);
        pbEditFirstName.setTooltipTypeface(FontUtils.getInstance().getDinAlternateBold());
        pbEditFirstName.setEditTextTypeface(FontUtils.getInstance().getDinAlternateBold());
        pbEditFirstName.setTextInputTypeface(FontUtils.getInstance().getDinAlternateBold());

        pbEditLastName.setInputType(InputType.TYPE_TEXT_FLAG_CAP_WORDS);
        pbEditLastName.setTooltipTypeface(FontUtils.getInstance().getDinAlternateBold());
        pbEditLastName.setEditTextTypeface(FontUtils.getInstance().getDinAlternateBold());
        pbEditLastName.setTextInputTypeface(FontUtils.getInstance().getDinAlternateBold());

        pbEditUserName.setInputType(InputType.TYPE_TEXT_FLAG_CAP_WORDS);
        pbEditUserName.setTooltipTypeface(FontUtils.getInstance().getDinAlternateBold());
        pbEditUserName.setEditTextTypeface(FontUtils.getInstance().getDinAlternateBold());
        pbEditUserName.setTextInputTypeface(FontUtils.getInstance().getDinAlternateBold());
    }

    private void setInputFieldImeListener() {
        pbEditFirstName.setImeActionListener((v, actionId, event) -> {
            pbEditLastName.requestTheFocus();
            return true;
        });

        pbEditLastName.setImeActionListener((v, actionId, event) -> {
            pbEditUserName.requestTheFocus();
            return true;
        });

        pbEditUserName.setImeActionListener((v, actionId, event) -> {
            KeyboardUtils.forceCloseKeyboard(pbEditUserName);
            return true;
        });
    }

    private void setInputFieldTextWatcher() {
        pbEditFirstName.setTextWatcher(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                pbEditFirstName.resetError();
                if (mPresenter.checkForChanges(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText())) {
                    mPresenter.validateFields(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText(), false);
                } else {
                    disableButton();
                }
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        pbEditLastName.setTextWatcher(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                pbEditLastName.resetError();
                if (mPresenter.checkForChanges(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText())) {
                    mPresenter.validateFields(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText(), false);
                } else {
                    disableButton();
                }
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        pbEditUserName.setTextWatcher(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                pbEditUserName.resetError();
                if (mPresenter.checkForChanges(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText())) {
                    mPresenter.validateFields(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText(), false);

                    if (ValidationUtils.isValidUsername(pbEditUserName.getText())) {
                        mPresenter.checkUserNameAvailable(pbEditUserName.getText());
                    }
                } else {
                    disableButton();
                }
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });
    }

    private void setData() {

        String firstName = PrefUtils.getInstance().getStringPref(PrefKey.FIRSTNAME);
        String lastName = PrefUtils.getInstance().getStringPref(PrefKey.LASTNAME);
        String userName = PrefUtils.getInstance().getStringPref(PrefKey.USERNAME);

        pbEditFirstName.setText(firstName);
        pbEditLastName.setText(lastName);
        pbEditUserName.setText(userName);
    }

    private void enableEdits() {
        if (isAdded()) {
            pbEditFirstName.setAlpha(1f);
            pbEditLastName.setAlpha(1f);
            pbEditUserName.setAlpha(1f);
            llEditEmail.setAlpha(1f);
            llEditPassword.setAlpha(1f);

            inputStopper.setVisibility(View.GONE);

            if (mPresenter.checkForChanges(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText())) {
                mPresenter.validateFields(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText(), false);
                if (ValidationUtils.isValidUsername(pbEditUserName.getText())) {
                    mPresenter.checkUserNameAvailable(pbEditUserName.getText());
                }
            } else {
                disableButton();
            }
        }
    }

    private void disableEdits() {
        pbEditFirstName.setAlpha(0.4f);
        pbEditLastName.setAlpha(0.4f);
        pbEditUserName.setAlpha(0.4f);
        llEditEmail.setAlpha(0.4f);
        llEditPassword.setAlpha(0.4f);

        inputStopper.setVisibility(View.VISIBLE);

        disableButton();
    }

    @Override
    public void showFirstNameError() {
        if (pbEditFirstName != null && isAdded()) {
            pbEditFirstName.showError(getString(R.string.first_name_error));
        }
    }

    @Override
    public void showLastNameError() {
        if (pbEditLastName != null && isAdded()) {
            pbEditLastName.showError(getString(R.string.last_name_error));
        }
    }

    @Override
    public void showInvalidUserNameError() {
        if (pbEditUserName != null && isAdded()) {
            pbEditUserName.showError(getString(R.string.user_name_error));
        }

    }

    @Override
    public void showUserNameNotAvailableError() {
        if (pbEditUserName != null && isAdded()) {
            pbEditUserName.showError(getString(R.string.user_name_unavailable));
        }
    }

    @Override
    public void enableButton() {

        String storedUserName = PrefUtils.getInstance().getStringPref(PrefKey.USERNAME);
        if (storedUserName == null) {
            storedUserName = "";
        }

        if (storedUserName.equals(pbEditUserName.getText()) || userNameAvailable) {
            btnSave.setAlpha(1.0f);
        }
    }

    @Override
    public void disableButton() {
        btnSave.setAlpha(0.2f);
    }

    @Override
    public void setUserNameAvailable(boolean isAvailable) {
        this.userNameAvailable = isAvailable;
        if (isAvailable && mPresenter.validateFields(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText(), false)) {
            enableButton();
        } else disableButton();
    }

    @Override
    public void showSingleButtonDialog(String error, String message) {
        if (mListener != null)
            mListener.showSingleButtonDialog(error, message, null);
    }

    @Override
    public void setPresenter(AccountDetailsContract.Presenter presenter) {
        if (presenter != null) {
            this.mPresenter = presenter;
        } else {
            throw new RuntimeException("Presenter is null");
        }
    }

    @Override
    public void goBack() {
        mListener.goBack();
    }

    @Override
    public void showLoader(String text) {
        if (isAdded() && !isDetached()) {
            btnSave.startMorphAnimation();
        }
    }

    @Override
    public void hideLoader() {
        if (isAdded()) {
            btnSave.revertAnimation(() -> null);
        }
    }

    @Override
    public void onUnknownError(String error) {
        if (mListener != null && isAdded()) {
            mListener.showSingleButtonDialog(getString(R.string.error), error, null);
        }
    }

    @Override
    public void onTimeout() {
        if (mListener != null && isAdded()) {
            mListener.showSingleButtonDialog(getString(R.string.timeout_title), getString(R.string.timeout_body), null);
        }
    }

    @Override
    public void onNetworkError() {
        if (mListener != null && isAdded()) {
            mListener.showSingleButtonDialog(getString(R.string.network_error_title), getString(R.string.network_error_body), null);
        }
    }

    @Override
    public void onConnectionError() {
        if (mListener != null && isAdded()) {
            mListener.showNoInternetHeader();
        }
    }

    @Override
    public void logoutUser() {
        mPresenter.clearUserData(mContext);

        if (mediaPlayerInterface.isPlaying()) {
            mediaPlayerInterface.stop();
        }
        PodcastStorageUtil.getInstance().clearStoredPodcast();
        mListener.startWalkThroughActivity();
    }

    @Override
    public boolean checkConnection() {
        return ConnectionUtils.userHasConnection(mContext);
    }

    public boolean onBackPressed(OnBackPressedOverrideListener listener) {

        if (mPresenter.checkForChanges(pbEditFirstName.getText(), pbEditLastName.getText(), pbEditUserName.getText())) {

            DialogUtils.showTwoButtonDialog(getString(R.string.are_you_sure), getString(R.string.are_you_sure_changes_will_be_lost), mContext, new TwoButtonDialogListener() {
                @Override
                public void onYesClicked() {
                    listener.override();
                }

                @Override
                public void onNoClicked() {
                }
            });
            return false;
        } else {
            return true;
        }
    }
}
