package ch.threema.app.threemasafe;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDialog;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.materialswitch.MaterialSwitch;

import org.slf4j.Logger;

import ch.threema.android.LifecycleAwareAsyncTask;
import ch.threema.app.R;
import ch.threema.app.dialogs.GenericProgressDialog;
import ch.threema.app.dialogs.ThreemaDialogFragment;
import ch.threema.app.managers.ServiceManager;
import ch.threema.android.textwatchers.SimpleTextWatcher;
import ch.threema.app.ui.interop.TextButtonPrimaryXml;
import ch.threema.app.utils.AnimationUtil;
import ch.threema.app.utils.DialogUtil;
import ch.threema.app.utils.EditTextUtil;
import ch.threema.base.ThreemaException;

import static ch.threema.base.utils.LoggingKt.getThreemaLogger;

import static ch.threema.app.utils.ActiveScreenLoggerKt.logScreenVisibility;

public class ThreemaSafeAdvancedDialog extends ThreemaDialogFragment implements View.OnClickListener {
    private static final Logger logger = getThreemaLogger("ThreemaSafeAdvancedDialog");

    private static final String ARG_SERVER_URL = "sU";
    private static final String ARG_PLAIN_STYLE = "pS";
    private static final String ARG_SERVER_USERNAME = "Un";
    private static final String ARG_SERVER_PASSWORD = "Sp";
    private static final String DIALOG_TAG_PROGRESS = "pr";

    private WizardDialogCallback callback;
    private Activity activity;
    private ThreemaSafeService threemaSafeService;
    private AlertDialog alertDialog;

    private ThreemaSafeServerInfo serverInfo;

    private @Nullable Button positiveButtonXml;
    private @Nullable TextButtonPrimaryXml positiveButtonCompose;
    private EditText serverUrlEditText, usernameEditText, passwordEditText;
    private LinearLayout serverContainer;
    private MaterialSwitch defaultServerSwitch;

    @NonNull
    public static ThreemaSafeAdvancedDialog newInstance(@NonNull ThreemaSafeServerInfo serverInfo, boolean plainStyle) {
        ThreemaSafeAdvancedDialog dialog = new ThreemaSafeAdvancedDialog();
        Bundle args = new Bundle();
        args.putString(ARG_SERVER_URL, serverInfo.getCustomServerName());
        args.putString(ARG_SERVER_USERNAME, serverInfo.getServerUsername());
        args.putString(ARG_SERVER_PASSWORD, serverInfo.getServerPassword());
        args.putBoolean(ARG_PLAIN_STYLE, plainStyle);
        dialog.setArguments(args);

        return dialog;
    }

    public interface WizardDialogCallback {
        void onYes(String tag, @NonNull ThreemaSafeServerInfo serverInfo);

        void onNo(String tag);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        logScreenVisibility(this, logger);

        try {
            callback = (WizardDialogCallback) getTargetFragment();
        } catch (ClassCastException e) {
            //
        }

        // called from an activity rather than a fragment
        if (callback == null) {
            if (!(activity instanceof WizardDialogCallback)) {
                throw new ClassCastException("Calling fragment must implement WizardDialogCallback interface");
            }
            callback = (WizardDialogCallback) activity;
        }
    }

    @Override
    public void onAttach(@NonNull Activity activity) {
        super.onAttach(activity);

        this.activity = activity;
    }

    @NonNull
    @Override
    public AppCompatDialog onCreateDialog(Bundle savedInstanceState) {
        serverInfo = new ThreemaSafeServerInfo();
        serverInfo.setCustomServerName(getArguments().getString(ARG_SERVER_URL));
        serverInfo.setServerUsername(getArguments().getString(ARG_SERVER_USERNAME));
        serverInfo.setServerPassword(getArguments().getString(ARG_SERVER_PASSWORD));
        boolean plainStyle = getArguments().getBoolean(ARG_PLAIN_STYLE);

        final View dialogView = activity.getLayoutInflater().inflate(
            plainStyle
                ? R.layout.dialog_safe_advanced
                : R.layout.dialog_wizard_safe_advanced,
            null
        );

        if (!plainStyle) {
            dialogView.findViewById(R.id.cancel_compose).setOnClickListener(v -> onCancel(null));
            positiveButtonCompose = dialogView.findViewById(R.id.ok_compose);
            positiveButtonCompose.setOnClickListener(v -> customOnClickedYes());
        }

        serverUrlEditText = dialogView.findViewById(R.id.safe_edit_server);
        serverContainer = dialogView.findViewById(R.id.safe_server_container);
        usernameEditText = dialogView.findViewById(R.id.safe_edit_username);
        passwordEditText = dialogView.findViewById(R.id.safe_edit_server_password);
        defaultServerSwitch = dialogView.findViewById(R.id.safe_switch_server);

        MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity(), getTheme());
        builder.setView(dialogView);

        try {
            threemaSafeService = ServiceManager.require().getThreemaSafeService();
        } catch (Exception e) {
            //
        }

        defaultServerSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
            updateUI();
        });

        if (serverInfo.isDefaultServer()) {
            serverContainer.setVisibility(View.GONE);
        }

        serverUrlEditText.setText(serverInfo.isDefaultServer() ? "" : serverInfo.getCustomServerName());
        usernameEditText.setText(serverInfo.getServerUsername());
        passwordEditText.setText(serverInfo.getServerPassword());
        defaultServerSwitch.setChecked(serverInfo.isDefaultServer());

        updateUI();

        serverUrlEditText.addTextChangedListener(new SimpleTextWatcher() {
            @Override
            public void onTextChanged(@NonNull CharSequence text, int start, int before, int count) {
                updatePositiveButtonEnabledState();
            }
        });

        if (plainStyle) {
            builder.setTitle(R.string.safe_configure_choose_server);
            builder.setPositiveButton(getString(R.string.ok), null);
            builder.setNegativeButton(getString(R.string.cancel), null);
        } else {
            updatePositiveButtonEnabledState();
        }

        setCancelable(false);

        alertDialog = builder.create();

        return alertDialog;
    }

    @Override
    public void onStart() {
        super.onStart();
        final @Nullable Button dialogPositiveButtonXml = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
        if (dialogPositiveButtonXml != null) {
            this.positiveButtonXml = dialogPositiveButtonXml;
            this.positiveButtonXml.setOnClickListener(this);
            alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(v -> onCancel(null));
            updatePositiveButtonEnabledState();
        } else {
            final @Nullable TextButtonPrimaryXml dialogPositiveButtonCompose = alertDialog.findViewById(R.id.ok_compose);
            final @Nullable TextButtonPrimaryXml dialogNegativeButtonCompose = alertDialog.findViewById(R.id.cancel_compose);
            if (dialogPositiveButtonCompose != null) {
                this.positiveButtonCompose = dialogPositiveButtonCompose;
                positiveButtonCompose.setOnClickListener(v -> customOnClickedYes());
            }
            if (dialogNegativeButtonCompose != null) {
                dialogNegativeButtonCompose.setOnClickListener(v -> onCancel(null));
            }
        }
    }

    private void updateUI() {
        updatePositiveButtonEnabledState();

        if (defaultServerSwitch.isChecked()) {
            if (serverContainer.getVisibility() == View.VISIBLE) {
                AnimationUtil.fadeViewVisibility(serverContainer, View.GONE);
            }
        } else {
            if (serverContainer.getVisibility() != View.VISIBLE) {
                AnimationUtil.fadeViewVisibility(serverContainer, View.VISIBLE);
            }
        }
    }

    private void updatePositiveButtonEnabledState() {
        if (serverUrlEditText != null && defaultServerSwitch != null) {
            final boolean isPositiveButtonEnabled = defaultServerSwitch.isChecked()
                || (serverUrlEditText.getText() != null && serverUrlEditText.getText().length() >= 9);
            if (positiveButtonXml != null) {
                positiveButtonXml.setEnabled(isPositiveButtonEnabled);
            } else if (positiveButtonCompose != null) {
                setPositiveButtonEnabled(isPositiveButtonEnabled);
            }
        }
    }

    private void setPositiveButtonEnabled(final boolean isEnabled) {
        if (positiveButtonCompose != null) {
            positiveButtonCompose.setButtonEnabled(isEnabled);
        }
    }

    @SuppressLint("StaticFieldLeak")
    private void testServer() {
        new LifecycleAwareAsyncTask<Void, String>() {
            @Override
            protected void onPreExecute() {
                if (serverUrlEditText != null) {
                    serverUrlEditText.setError(null);
                }
                GenericProgressDialog.newInstance(R.string.safe_test_server, R.string.please_wait).show(getFragmentManager(), DIALOG_TAG_PROGRESS);
            }

            @Override
            protected String doInBackground(Void params) {
                try {
                    threemaSafeService.testServer(serverInfo);
                    return null;
                } catch (ThreemaException e) {
                    logger.error("Failed to test server", e);
                    return e.getMessage();
                }
            }

            @Override
            protected void onPostExecute(@Nullable String failureMessage) {
                DialogUtil.dismissDialog(getFragmentManager(), DIALOG_TAG_PROGRESS, true);

                if (failureMessage != null) {
                    if (serverUrlEditText != null) {
                        serverUrlEditText.setError(getString(R.string.threema_safe_test_unsuccessful, failureMessage));
                    }
                } else {
                    onYes();
                }

                updateUI();
            }
        }.execute(this, null);
    }

    private void onYes() {
        dismiss();
        callback.onYes(getTag(), serverInfo);
    }

    @Override
    public void onCancel(DialogInterface dialogInterface) {
        dismiss();
        callback.onNo(this.getTag());
    }

    @Override
    public void onClick(View v) {
        customOnClickedYes();
    }

    private void customOnClickedYes() {
        if (!defaultServerSwitch.isChecked()) {
            EditTextUtil.hideSoftKeyboard(serverUrlEditText);
            serverInfo.setCustomServerName(serverUrlEditText.getText().toString());
            serverInfo.setServerUsername(usernameEditText.getText().toString());
            serverInfo.setServerPassword(passwordEditText.getText().toString());
            testServer();
        } else {
            serverInfo = new ThreemaSafeServerInfo();
            onYes();
        }
    }
}
