package org.commcare.views.dialogs;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.TextView;

import org.commcare.activities.CommCareActivity;
import org.commcare.dalvik.R;
import org.javarosa.core.services.locale.Localization;

/**
 * Any progress dialog associated with a CommCareTask should use
 * this class to implement the dialog. Any class that launches such a task
 * should implement the generateProgressDialog() method of the DialogController
 * interface, and create the dialog in that method. The rest of the dialog's
 * lifecycle is handled by methods of the DialogController interface that are
 * fully implemented in CommCareActivity
 *
 * @author amstone326
 */
public class CustomProgressDialog extends DialogFragment {

    //keys for onSaveInstanceState
    private final static String KEY_TITLE = "title";
    private final static String KEY_MESSAGE = "message";
    private final static String KEY_USING_CB = "using_checkbox";
    private final static String KEY_IS_CHECKED = "is_checked";
    private final static String KEY_CB_TEXT = "checkbox_text";
    private final static String KEY_USING_BUTTON = "using_cancel_buton";
    private final static String KEY_TASK_ID = "task_id";
    private final static String KEY_CANCELABLE = "is_cancelable";
    private final static String KEY_WAS_CANCEL_PRESSED = "was_cancel_pressed";
    private final static String KEY_USING_PROGRESS_BAR = "using_progress_bar";
    private final static String KEY_PROGRESS_BAR_PROGRESS = "progress_bar_progress";
    private final static String KEY_PROGRESS_BAR_MAX = "progress_bar_max";
    private final static String KEY_PROGRESS_BAR_VISIBILITY = "progress_bar_visibility";

    //id of the task that spawned this dialog, -1 if not associated with a CommCareTask
    private int taskId;

    //for all dialogs
    private String title;
    private String message;
    private boolean isCancelable; //default is false, only set to true if setCancelable() is explicitly called
    private boolean wasCancelPressed;

    //for checkboxes
    private boolean usingCheckbox;
    private boolean isChecked;
    private String checkboxText;

    //for cancel button
    private boolean usingCancelButton;
    private Button cancelButton;

    //for progress bar
    private boolean usingHorizontalProgressBar;
    private boolean progressBarIsVisible;
    private int progressBarProgress;
    private int progressBarMax;

    public static CustomProgressDialog newInstance(String title, String message, int taskId) {
        CustomProgressDialog frag = new CustomProgressDialog();
        frag.title = title;
        frag.message = message;
        frag.taskId = taskId;
        return frag;
    }

    public void addCheckbox(String text, boolean isChecked) {
        this.usingCheckbox = true;
        this.checkboxText = text;
        this.isChecked = isChecked;
    }

    public void addCancelButton() {
        usingCancelButton = true;
    }

    public void removeCancelButton() {
        usingCancelButton = false;
        if (cancelButton != null) {
            cancelButton.setVisibility(View.INVISIBLE);
        }
    }

    public void setCancelable() {
        this.isCancelable = true;
    }

    public void addProgressBar() {
        this.usingHorizontalProgressBar = true;
        this.progressBarIsVisible = true;
        this.progressBarProgress = 0;
        this.progressBarMax = 0;
    }

    public int getTaskId() {
        return taskId;
    }

    public boolean isChecked() {
        return isChecked;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        restoreFields(savedInstanceState);
    }

    private void restoreFields(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            this.title = savedInstanceState.getString(KEY_TITLE);
            this.message = savedInstanceState.getString(KEY_MESSAGE);
            this.usingCheckbox = savedInstanceState.getBoolean(KEY_USING_CB);
            this.isChecked = savedInstanceState.getBoolean(KEY_IS_CHECKED);
            this.checkboxText = savedInstanceState.getString(KEY_CB_TEXT);
            this.usingCancelButton = savedInstanceState.getBoolean(KEY_USING_BUTTON);
            this.taskId = savedInstanceState.getInt(KEY_TASK_ID);
            this.isCancelable = savedInstanceState.getBoolean(KEY_CANCELABLE);
            this.wasCancelPressed = savedInstanceState.getBoolean(KEY_WAS_CANCEL_PRESSED);
            this.usingHorizontalProgressBar = savedInstanceState.getBoolean(KEY_USING_PROGRESS_BAR);
            this.progressBarProgress = savedInstanceState.getInt(KEY_PROGRESS_BAR_PROGRESS);
            this.progressBarMax = savedInstanceState.getInt(KEY_PROGRESS_BAR_MAX);
            this.progressBarIsVisible = savedInstanceState.getBoolean(KEY_PROGRESS_BAR_VISIBILITY);
        }
    }

    @Override
    public void onDestroyView() {
        if (getDialog() != null && getRetainInstance()) {
            getDialog().setDismissMessage(null);
        }
        super.onDestroyView();
    }


    /* Creates the dialog that will reside within the fragment */
    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        restoreFields(savedInstanceState);
        Context context = getActivity();
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        setCancelable(isCancelable);

        View view;
        if (usingHorizontalProgressBar) {
            view = LayoutInflater.from(context).inflate(R.layout.progress_dialog_determinate, null);
            setupDeterminateView(view);
        } else {
            view = LayoutInflater.from(context).inflate(R.layout.progress_dialog_indeterminate, null);
        }

        TextView titleView = view.findViewById(R.id.progress_dialog_title).findViewById(R.id.dialog_title_text);
        titleView.setText(title);
        TextView messageView = view.findViewById(R.id.progress_dialog_message);
        messageView.setText(message);

        if (usingCancelButton) {
            cancelButton = setupCancelButton(view);
            if (wasCancelPressed) {
                setCancellingText(titleView, messageView, cancelButton);
            }
        }

        builder.setView(view);
        Dialog d = builder.create();
        d.setCanceledOnTouchOutside(isCancelable);

        return d;
    }

    private void setupDeterminateView(View view) {
        ProgressBar bar = view.findViewById(R.id.progress_bar_horizontal);
        bar.setProgress(progressBarProgress);
        bar.setMax(progressBarMax);
        if (progressBarIsVisible) {
            bar.setVisibility(View.VISIBLE);
        } else {
            bar.setVisibility(View.GONE);
        }

        if (usingCheckbox) {
            CheckBox cb = view.findViewById(R.id.progress_dialog_checkbox);
            cb.setVisibility(View.VISIBLE);
            cb.setText(checkboxText);
            cb.setOnClickListener(v -> isChecked = ((CheckBox)v).isChecked());
            if (isChecked) {
                cb.toggle();
            }
        }
    }

    private Button setupCancelButton(View v) {
        Button b = v.findViewById(R.id.dialog_cancel_button);
        b.setOnClickListener(v1 -> {
            ((CommCareActivity)getActivity()).cancelCurrentTask();
            showCancelledState();
        });
        b.setVisibility(View.VISIBLE);
        return b;
    }

    private void showCancelledState() {
        wasCancelPressed = true;

        AlertDialog pd = (AlertDialog)getDialog();
        if (pd != null) {
            TextView titleView = pd.findViewById(R.id.progress_dialog_title).findViewById(R.id.dialog_title_text);
            TextView messageView = pd.findViewById(R.id.progress_dialog_message);
            Button cancelButton = pd.findViewById(R.id.dialog_cancel_button);
            setCancellingText(titleView, messageView, cancelButton);
        }
    }

    private void setCancellingText(TextView titleTextView, TextView messageTextView, Button cancelButton) {
        titleTextView.setText(Localization.get("activity.task.cancelling.title", new String[]{title}));
        messageTextView.setText(Localization.get("activity.task.cancelling.message"));
        cancelButton.setEnabled(false);
    }

    public void updateTitle(String newTitle) {
        this.title = newTitle;
        updateTextView(newTitle, R.id.dialog_title_text);
    }

    public void updateMessage(String newMessage) {
        this.message = newMessage;
        updateTextView(newMessage, R.id.progress_dialog_message);
    }

    private void updateTextView(String newText, int idOfViewToUpdate) {
        AlertDialog dialog = (AlertDialog)getDialog();
        if (dialog != null) {
            TextView tv = dialog.findViewById(idOfViewToUpdate);
            tv.setText(newText);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(KEY_TITLE, this.title);
        outState.putString(KEY_MESSAGE, this.message);
        outState.putBoolean(KEY_USING_CB, this.usingCheckbox);
        outState.putBoolean(KEY_IS_CHECKED, this.isChecked);
        outState.putString(KEY_CB_TEXT, this.checkboxText);
        outState.putBoolean(KEY_USING_BUTTON, this.usingCancelButton);
        outState.putInt(KEY_TASK_ID, this.taskId);
        outState.putBoolean(KEY_CANCELABLE, this.isCancelable);
        outState.putBoolean(KEY_WAS_CANCEL_PRESSED, this.wasCancelPressed);
        outState.putBoolean(KEY_USING_PROGRESS_BAR, this.usingHorizontalProgressBar);
        outState.putInt(KEY_PROGRESS_BAR_PROGRESS, this.progressBarProgress);
        outState.putInt(KEY_PROGRESS_BAR_MAX, this.progressBarMax);
        outState.putBoolean(KEY_PROGRESS_BAR_VISIBILITY, this.progressBarIsVisible);
    }

    public void updateProgressBarVisibility(boolean visible) {
        if (usingHorizontalProgressBar) {
            progressBarIsVisible = visible;
            Dialog dialog = getDialog();
            if (dialog != null) {
                ProgressBar bar = dialog.findViewById(R.id.progress_bar_horizontal);
                if (progressBarIsVisible) {
                    bar.setVisibility(View.VISIBLE);
                } else {
                    bar.setVisibility(View.GONE);
                }
            }
        }
    }

    public void updateProgressBar(int progress, int max) {
        if (usingHorizontalProgressBar) {
            updateProgressBarVisibility(true);
            this.progressBarProgress = progress;
            this.progressBarMax = max;
            Dialog dialog = getDialog();
            if (dialog != null) {
                ProgressBar bar = dialog.findViewById(R.id.progress_bar_horizontal);
                bar.setProgress(progress);
                bar.setMax(max);
            }
        }
    }
}