package com.app.simplitend.patientprofile.setuproutine;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.app.TimePickerDialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;

import com.app.simplitend.R;
import com.app.simplitend.apputils.AppUtil;
import com.app.simplitend.databinding.AddRoutineFragmentBinding;
import com.app.simplitend.patientprofile.ProfileContracts;
import com.app.simplitend.patientprofile.setuproutine.mvvm.RoutineDetails;
import com.app.simplitend.patientprofile.setuproutine.mvvm.RoutineViewModel;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone;

public class AddRoutineFragment extends Fragment implements CompoundButton.OnCheckedChangeListener,
        ProfileContracts.AddNUpdateRoutineCallback {

    // view binding
    protected AddRoutineFragmentBinding binding;

    private boolean[] week_state;

    public static final String ROUTINE_KEY = "routine_key";
    private RoutineDetails routine;

    private RoutineViewModel routineViewModel;

    private ProgressDialog progressDialog;

    public AddRoutineFragment() {
        // required empty const.
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = AddRoutineFragmentBinding.inflate(inflater, container, false);

        routineViewModel = new ViewModelProvider(requireActivity()).get(RoutineViewModel.class);

        initViews();

        clickEvents();

        return binding.getRoot();
    }

    @SuppressLint("ClickableViewAccessibility")
    private void initViews() {

        progressDialog = new ProgressDialog(requireContext());

        setUpWeekSelection();

        Bundle bundle = getArguments();

        if (bundle != null && bundle.getSerializable(ROUTINE_KEY) != null){
            routine = (RoutineDetails) bundle.getSerializable(ROUTINE_KEY);
            setLayoutDetails();
        }else{
            // selecting default week day as current
            Calendar calendar = Calendar.getInstance();
            int day_of_week = calendar.get(Calendar.DAY_OF_WEEK) - 1;

            setSelectionState(day_of_week, week_state[day_of_week] = true);
        }

        // scrolling instruction edit text
        binding.routineDescription.setOnTouchListener((v, event) -> {
            if (binding.routineDescription.hasFocus()) {
                v.getParent().requestDisallowInterceptTouchEvent(true);
                if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_SCROLL) {
                    v.getParent().requestDisallowInterceptTouchEvent(false);
                    return true;
                }
            }
            return false;
        });

        binding.everydayCheck.setOnCheckedChangeListener(this);

    }

    private void setLayoutDetails() {
        if (routine == null) return;

        binding.title.setText(getString(R.string.edit_routine));
        binding.addRoutine.setText(getString(R.string.save));

        binding.routineName.setText(routine.routine_title);
        binding.routineDescription.setText(routine.routine_description);

        SimpleDateFormat input_sdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
        SimpleDateFormat output_sdf = new SimpleDateFormat("hh:mm a", Locale.getDefault());

        String start_time, end_time;

        try {
            Date start_date = input_sdf.parse(routine.routine_start_time);
            start_time = output_sdf.format(Objects.requireNonNull(start_date));

            Date end_date = input_sdf.parse(routine.routine_end_time);
            end_time = output_sdf.format(Objects.requireNonNull(end_date));
        } catch (Exception e) {
            start_time = routine.routine_start_time;
            end_time = routine.routine_end_time;
        }

        binding.startTime.setText(start_time);
        binding.endTime.setText(end_time);

        binding.startTime.setHint(routine.routine_start_time);
        binding.endTime.setHint(routine.routine_end_time);

        setSelectionState(0, week_state[0] = routine.sun.equals("1"));
        setSelectionState(1, week_state[1] = routine.mon.equals("1"));
        setSelectionState(2, week_state[2] = routine.tue.equals("1"));
        setSelectionState(3, week_state[3] = routine.wed.equals("1"));
        setSelectionState(4, week_state[4] = routine.thu.equals("1"));
        setSelectionState(5, week_state[5] = routine.fri.equals("1"));
        setSelectionState(6, week_state[6] = routine.sat.equals("1"));

    }

    private void clickEvents() {
        binding.backBtn.setOnClickListener(v -> {
            if (getActivity() != null){
                getActivity().onBackPressed();
            }
        });

        binding.startTime.setOnClickListener(v -> {
            AppUtil.closeKeyboard(requireActivity());
            binding.startTime.setError(null);

            Date selected_date = null;

            if (!binding.startTime.getText().toString().trim().isEmpty()){
                SimpleDateFormat sdf = new SimpleDateFormat("hh:mm a", Locale.getDefault());
                try {
                    selected_date = sdf.parse(binding.startTime.getText().toString().trim());
                }catch (Exception e){
                    // do nothing
                }
            }

            getTime(binding.startTime, selected_date);
        });

        binding.endTime.setOnClickListener(v -> {
            AppUtil.closeKeyboard(requireActivity());
            binding.endTime.setError(null);

            Date selected_date = null;

            if (!binding.endTime.getText().toString().trim().isEmpty()){
                SimpleDateFormat sdf = new SimpleDateFormat("hh:mm a", Locale.getDefault());
                try {
                    selected_date = sdf.parse(binding.endTime.getText().toString().trim());
                }catch (Exception e){
                    // do nothing
                }
            }

            getTime(binding.endTime, selected_date);
        });

        binding.addRoutine.setOnClickListener(v -> {
            AppUtil.closeKeyboard(requireActivity());

//            DateTimeZone dateTimeZone = DateTimeZone.getDefault();
//
//            // Get the GMT offset in milliseconds
//            int gmtOffsetMillis = dateTimeZone.getOffset(adakTime);
//
//            // Calculate the GMT offset in hours and minutes
//            int gmtOffsetHours = gmtOffsetMillis / 3600000;
//            int gmtOffsetMinutes = (gmtOffsetMillis % 3600000) / 60000;

            if (allOkay()) {

                if (routine != null){
                    AppUtil.showSOSDecision(requireContext(), getString(R.string.make_changes),
                            getString(R.string.yes), getString(R.string.no),
                            v1 -> {
                                // yes click
                                addRoutine();
                            }, v2 -> {
                                // no click
                            });
                }else{
                    addRoutine();
                }
            }
        });

    }

    private void addRoutine() {

        progressDialog.setTitle("Please wait...");
        progressDialog.setMessage("while we save your reminder.");
        progressDialog.setCancelable(false);
        progressDialog.show();

        RoutineDetails routineDetails = new RoutineDetails();

        routineDetails.routine_title = binding.routineName.getText().toString().trim();
        routineDetails.routine_description = binding.routineDescription.getText().toString().trim();

        // saving the actual format of time i.e. HH:mm:ss as hint
        // and saving the formatted time as text i.e. hh:mm a
        routineDetails.routine_start_time = binding.startTime.getHint().toString();
        routineDetails.routine_end_time = binding.endTime.getHint().toString();

        routineDetails.sun = week_state[0] ? "1" : "0";
        routineDetails.mon = week_state[1] ? "1" : "0";
        routineDetails.tue = week_state[2] ? "1" : "0";
        routineDetails.wed = week_state[3] ? "1" : "0";
        routineDetails.thu = week_state[4] ? "1" : "0";
        routineDetails.fri = week_state[5] ? "1" : "0";
        routineDetails.sat = week_state[6] ? "1" : "0";

        if (routine != null) {
            // this intent is to update the reminder
            routineDetails.is_update = 1;
            routineDetails.patientRoutineId = routine.id;
            routineDetails.routine_marked = routine.routine_marked;
        } else {
            routineDetails.is_update = 0;
        }

        String token = "Bearer " + AppUtil.getPatientToken(requireContext());

        routineViewModel.addNUpdateRoutine(AppUtil.getPatientUid(requireContext()),
                routineDetails,
                token,
                this);

    }

    private boolean allOkay() {
        boolean allOkay = true;

        if (binding.routineName.getText().toString().trim().isEmpty()){
            allOkay = false;
            binding.routineName.setError("Required");
        }

        if (binding.startTime.getText().toString().trim().isEmpty()){
            allOkay = false;
            binding.startTime.setError("Required");
        }

        if (binding.endTime.getText().toString().trim().isEmpty()){
            allOkay = false;
            binding.endTime.setError("Required");
        }

        if (allOkay){
            SimpleDateFormat sdf = new SimpleDateFormat("hh:mm a", Locale.getDefault());

            try {
                Date start_date = sdf.parse(binding.startTime.getText().toString().trim());
                Date end_date = sdf.parse(binding.endTime.getText().toString().trim());

                if (start_date == null || end_date == null) throw new Exception();

                if (start_date.getTime() >= end_date.getTime()){
                    Toast.makeText(requireContext(), "Emd time should be greater than start time.", Toast.LENGTH_SHORT).show();
                    allOkay = false;
                }

            } catch (Exception e) {
                // do nothing
            }

        }

        if (allOkay) {
            boolean anyOneSelected = false;
            for (int i = 0; i < week_state.length; i++) {
                if (week_state[i]) {
                    // this week day is selected
                    anyOneSelected = true;
                    break;
                }
            }

            if (!anyOneSelected) {
                // none are selected
                allOkay = false;
                Toast.makeText(requireContext(), "Select a week day.", Toast.LENGTH_SHORT).show();
            }
        }

        return allOkay;
    }

    // set selection and un-selection of week day
    private void setUpWeekSelection() {

        week_state = new boolean[7];

        // week day selections
        binding.sun.setOnClickListener(v -> setSelectionState(0, week_state[0] = !week_state[0]));
        binding.mon.setOnClickListener(v -> setSelectionState(1, week_state[1] = !week_state[1]));
        binding.tue.setOnClickListener(v -> setSelectionState(2, week_state[2] = !week_state[2]));
        binding.wed.setOnClickListener(v -> setSelectionState(3, week_state[3] = !week_state[3]));
        binding.thu.setOnClickListener(v -> setSelectionState(4, week_state[4] = !week_state[4]));
        binding.fri.setOnClickListener(v -> setSelectionState(5, week_state[5] = !week_state[5]));
        binding.sat.setOnClickListener(v -> setSelectionState(6, week_state[6] = !week_state[6]));

    }

    // shows time picker and sets the time picked into @textview
    // shows time picker to pick time and set to textview
    private void getTime(TextView textView, Date selected_date) {

        Calendar calendar = Calendar.getInstance(Locale.getDefault());

        if (selected_date != null){
            calendar.setTime(selected_date);
        }

        TimePickerDialog tpd = new TimePickerDialog(requireContext(),
                (view, hourOfDay, minute) -> {

                    Calendar cal = Calendar.getInstance();
                    cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
                    cal.set(Calendar.MINUTE, minute);

                    SimpleDateFormat sdf = new SimpleDateFormat("hh:mm a", Locale.getDefault());
                    SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());

                    String selected_time = sdf.format(cal.getTime());
                    textView.setText(selected_time);
                    textView.setHint(sdf2.format(cal.getTime()));

                }, calendar.getTime().getHours(), calendar.getTime().getMinutes(), false);

        tpd.show();

    }

    private void setSelectionState(int position, boolean selection) {
        if (selection) {
            // selection has to be made
            switch (position) {
                case 0:
                    // sun
                    binding.sun.setBackgroundTintList(AppCompatResources.getColorStateList(requireContext(), R.color.color_primary));
                    binding.sun.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.white_bg));
                    break;
                case 1:
                    // mon
                    binding.mon.setBackgroundTintList(AppCompatResources.getColorStateList(requireContext(), R.color.color_primary));
                    binding.mon.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.white_bg));
                    break;
                case 2:
                    // tue
                    binding.tue.setBackgroundTintList(AppCompatResources.getColorStateList(requireContext(), R.color.color_primary));
                    binding.tue.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.white_bg));
                    break;
                case 3:
                    // wed
                    binding.wed.setBackgroundTintList(AppCompatResources.getColorStateList(requireContext(), R.color.color_primary));
                    binding.wed.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.white_bg));
                    break;
                case 4:
                    // thu
                    binding.thu.setBackgroundTintList(AppCompatResources.getColorStateList(requireContext(), R.color.color_primary));
                    binding.thu.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.white_bg));
                    break;
                case 5:
                    // fri
                    binding.fri.setBackgroundTintList(AppCompatResources.getColorStateList(requireContext(), R.color.color_primary));
                    binding.fri.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.white_bg));
                    break;
                case 6:
                    // sat
                    binding.sat.setBackgroundTintList(AppCompatResources.getColorStateList(requireContext(), R.color.color_primary));
                    binding.sat.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.white_bg));
                    break;
            }
        } else {
            // un-selection has to be made
            switch (position) {
                case 0:
                    // sun
                    binding.sun.setBackgroundTintList(null);
                    binding.sun.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.black));
                    break;
                case 1:
                    // mon
                    binding.mon.setBackgroundTintList(null);
                    binding.mon.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.black));
                    break;
                case 2:
                    // tue
                    binding.tue.setBackgroundTintList(null);
                    binding.tue.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.black));
                    break;
                case 3:
                    // wed
                    binding.wed.setBackgroundTintList(null);
                    binding.wed.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.black));
                    break;
                case 4:
                    // thu
                    binding.thu.setBackgroundTintList(null);
                    binding.thu.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.black));
                    break;
                case 5:
                    // fri
                    binding.fri.setBackgroundTintList(null);
                    binding.fri.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.black));
                    break;
                case 6:
                    // sat
                    binding.sat.setBackgroundTintList(null);
                    binding.sat.setTextColor(AppCompatResources.getColorStateList(requireContext(), R.color.black));
                    break;
            }
        }

        // checking if all days are selected or not
        // thus, updating the Everyday switch accordingly
        boolean isEveryDay = true;

        for (int i = 0; i < 7; i++) {
            if (!week_state[i]) {
                // some day is not selected thus not everyday selection
                isEveryDay = false;
                break;
            }
        }

        binding.everydayCheck.setOnCheckedChangeListener(null);
        binding.everydayCheck.setChecked(isEveryDay);
        binding.everydayCheck.setOnCheckedChangeListener(this);
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        for (int i = 0; i < 7; i++) {
            setSelectionState(i, week_state[i] = isChecked);
        }
    }


    // add update routine callback
    @Override
    public void onRoutineAdded(RoutineDetails medicationInfo) {
        progressDialog.dismiss();

        if (this.routine == null) {
            Toast.makeText(requireContext(), "Activity saved successfully.", Toast.LENGTH_SHORT).show();

            Activity activity = getActivity();
            if (activity != null){
                activity.onBackPressed();
            }

        } else {

            AppUtil.showAnimateDBS(requireContext(),
                    getString(R.string.changes_successful), R.raw.done_anim_primary,
                    3600, v3 -> {
                        // here v3 is null
                        Activity activity = getActivity();
                        if (activity != null){
                            activity.onBackPressed();
                        }
                    });
        }
    }

    @Override
    public void onRoutineAddFailed(Throwable t, String message) {
        progressDialog.dismiss();
        AppUtil.showAlert(requireContext(),
                getString(R.string.something_went_wrong),
                message,
                getString(R.string.ok),
                ((dialog, which) -> {
                    dialog.dismiss();
                }), null, null);
    }
}
