package com.app.simplitend.patientprofile.medreminder;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.app.simplitend.R;
import com.app.simplitend.apputils.AppUtil;
import com.app.simplitend.caregiverdashboard.mvvm.CaregiverMainViewModel;
import com.app.simplitend.databinding.RemindersFragmentBinding;
import com.app.simplitend.patientprofile.ProfileContracts;
import com.app.simplitend.patientprofile.medreminder.mvvm.ReminderAdapter;
import com.app.simplitend.patientprofile.medreminder.mvvm.ReminderViewModel;
import com.app.simplitend.patientprofile.medreminder.mvvm.models.ReminderResult;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class ReminderFragment extends Fragment implements RecyclerTouchListener.OnSwipeOptionsClickListener,
        ProfileContracts.GetRemindersListCallback, ProfileContracts.ReminderDeleteCallback,
        ProfileContracts.AddReminderCallBack,
        ReminderAdapter.ReminderCheckClickListener,
        ReminderAdapter.ReminderClickListener {

    // view binding
    protected RemindersFragmentBinding binding;

    // reminders viewmodel
    protected ReminderViewModel reminderViewModel;

    // recycler touch listener for swipe menu
    protected RecyclerTouchListener recyclerTouchListener;

    private ArrayList<WeekDayViewHolder> weekDayViewsList;

    private ReminderAdapter reminderAdapter;

    private ProgressDialog progressDialog;

    private ArrayList<ReminderResult> remindersList;

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

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = RemindersFragmentBinding.inflate(inflater, container, false);
        reminderViewModel = new ViewModelProvider(requireActivity()).get(ReminderViewModel.class);

        initViews();

        clickEvents();

        return binding.getRoot();
    }

    private void clickEvents() {

        // date selections
        binding.day.setOnClickListener(v -> {
            setDayOfWeek(0);
            loadReminderList(weekDayViewsList.get(0).day_of_week);
        });
        binding.day2.setOnClickListener(v -> {
            setDayOfWeek(1);
            loadReminderList(weekDayViewsList.get(1).day_of_week);
        });
        binding.day3.setOnClickListener(v -> {
            setDayOfWeek(2);
            loadReminderList(weekDayViewsList.get(2).day_of_week);
        });
        binding.day4.setOnClickListener(v -> {
            setDayOfWeek(3);
            loadReminderList(weekDayViewsList.get(3).day_of_week);
        });
        binding.day5.setOnClickListener(v -> {
            setDayOfWeek(4);
            loadReminderList(weekDayViewsList.get(4).day_of_week);
        });
        binding.day6.setOnClickListener(v -> {
            setDayOfWeek(5);
            loadReminderList(weekDayViewsList.get(5).day_of_week);
        });
        binding.day7.setOnClickListener(v -> {
            setDayOfWeek(6);
            loadReminderList(weekDayViewsList.get(6).day_of_week);
        });

        // add button
        binding.addReminder.setOnClickListener(v ->
                {

                    try {
                        Navigation.findNavController(v).navigate(R.id.action_reminderFragment_to_addReminderFragment);
                    } catch (Exception e) {
                        // there may be a IllegalStateException as this same fragment is used from another fragment
                        // and not through the nav graph

                        try {
                            getParentFragmentManager().beginTransaction()
                                    .replace(R.id.fcv_profile_shower, AddReminderFragment.class, null)
                                    .addToBackStack("add_reminder")
                                    .commit();
                        } catch (Exception ex) {
                            // user may be out of context
                        }
                    }
                }
        );

        binding.done.setOnClickListener(v -> {
            if (getActivity() != null) {
                getActivity().onBackPressed();
            }
        });

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

    }

    private void loadReminderList(int day_of_week) {
        progressDialog.setTitle("Please wait...");
        progressDialog.setMessage("while we fetch reminders list for you.");
        progressDialog.setCancelable(false);
        progressDialog.show();

        day_of_week--; // because, at server side day_of_week starts from 0

        String token = "Bearer " + AppUtil.getPatientToken(requireContext());
        int patient_uid = AppUtil.getPatientUid(requireContext());
        reminderViewModel.getRemindersList(patient_uid, day_of_week, token, this);
    }

    private void initViews() {

        progressDialog = new ProgressDialog(requireContext());

        binding.remindersRv.setLayoutManager(new LinearLayoutManager(requireContext()));
        remindersList = new ArrayList<>();
        reminderAdapter = new ReminderAdapter(remindersList);
        reminderAdapter.setCheckClickListener(this);
        reminderAdapter.setReminderClickListener(this);
        binding.remindersRv.setAdapter(reminderAdapter);

        recyclerTouchListener = new RecyclerTouchListener(requireActivity(), binding.remindersRv);

        recyclerTouchListener.setSwipeOptionViews(R.id.reminder_edit, R.id.reminder_delete)
                .setSwipeable(R.id.rowFG, R.id.rowBG, this);

        binding.remindersRv.addOnItemTouchListener(recyclerTouchListener);

        Calendar calendar = Calendar.getInstance();

        String today_date = reminderViewModel.getMonthOfYear(calendar.get(Calendar.MONTH) + 1);
        today_date = today_date.concat(", " + calendar.get(Calendar.DAY_OF_MONTH));

        binding.todayDate.setText(today_date);

        // show days of week
        setDayOfWeekViews();

        setDayOfWeek(reminderViewModel.selected_dow = 0);
        loadReminderList(weekDayViewsList.get(reminderViewModel.selected_dow).day_of_week);
    }

    private void setDayOfWeekViews() {
        weekDayViewsList = new ArrayList<>();

        // adding all day_views to the list
        WeekDayViewHolder day1 = new WeekDayViewHolder(binding.day, binding.dayT1, binding.dayT2);
        weekDayViewsList.add(day1);

        WeekDayViewHolder day2 = new WeekDayViewHolder(binding.day2, binding.day2T1, binding.day2T2);
        weekDayViewsList.add(day2);

        WeekDayViewHolder day3 = new WeekDayViewHolder(binding.day3, binding.day31, binding.day32);
        weekDayViewsList.add(day3);

        WeekDayViewHolder day4 = new WeekDayViewHolder(binding.day4, binding.day41, binding.day42);
        weekDayViewsList.add(day4);

        WeekDayViewHolder day5 = new WeekDayViewHolder(binding.day5, binding.day51, binding.day52);
        weekDayViewsList.add(day5);

        WeekDayViewHolder day6 = new WeekDayViewHolder(binding.day6, binding.day61, binding.day62);
        weekDayViewsList.add(day6);

        WeekDayViewHolder day7 = new WeekDayViewHolder(binding.day7, binding.day71, binding.day72);
        weekDayViewsList.add(day7);

        Calendar calendar = Calendar.getInstance();

        for (int i = 0; i < 7; i++) {
            WeekDayViewHolder dayViewHolder = weekDayViewsList.get(i);

            dayViewHolder.day_of_week = calendar.get(Calendar.DAY_OF_WEEK);
            dayViewHolder.day.setText(reminderViewModel.getDayOfWeek(dayViewHolder.day_of_week - 1));
            dayViewHolder.date.setText(String.valueOf(calendar.get(Calendar.DAY_OF_MONTH)));
            dayViewHolder.mDate = calendar.getTime();

            calendar.add(Calendar.DAY_OF_WEEK, 1);
        }
    }

    private void clearSelection() {
        switch (reminderViewModel.selected_dow) {
            case 0:
                binding.day.setBackgroundColor(getResources().getColor(R.color.white_bg));
                binding.dayT1.setTextColor(getResources().getColor(R.color.black));
                binding.dayT2.setTextColor(getResources().getColor(R.color.black));
                break;
            case 1:

                binding.day2.setBackgroundColor(getResources().getColor(R.color.white_bg));
                binding.day2T1.setTextColor(getResources().getColor(R.color.black));
                binding.day2T2.setTextColor(getResources().getColor(R.color.black));
                break;
            case 2:

                binding.day3.setBackgroundColor(getResources().getColor(R.color.white_bg));
                binding.day31.setTextColor(getResources().getColor(R.color.black));
                binding.day32.setTextColor(getResources().getColor(R.color.black));
                break;
            case 3:

                binding.day4.setBackgroundColor(getResources().getColor(R.color.white_bg));
                binding.day41.setTextColor(getResources().getColor(R.color.black));
                binding.day42.setTextColor(getResources().getColor(R.color.black));
                break;
            case 4:

                binding.day5.setBackgroundColor(getResources().getColor(R.color.white_bg));
                binding.day51.setTextColor(getResources().getColor(R.color.black));
                binding.day52.setTextColor(getResources().getColor(R.color.black));
                break;
            case 5:

                binding.day6.setBackgroundColor(getResources().getColor(R.color.white_bg));
                binding.day61.setTextColor(getResources().getColor(R.color.black));
                binding.day62.setTextColor(getResources().getColor(R.color.black));
                break;
            case 6:

                binding.day7.setBackgroundColor(getResources().getColor(R.color.white_bg));
                binding.day71.setTextColor(getResources().getColor(R.color.black));
                binding.day72.setTextColor(getResources().getColor(R.color.black));
                break;
        }
    }

    private void setDayOfWeek(int selection) {

        // setting selected date in adapter
        reminderAdapter.setSelected_date(weekDayViewsList.get(selection).mDate);

        clearSelection();

        switch (reminderViewModel.selected_dow = selection) {
            case 0:
                binding.day.setBackgroundResource(R.drawable.seleted_item_primary);
                binding.dayT1.setTextColor(getResources().getColor(R.color.white_bg));
                binding.dayT2.setTextColor(getResources().getColor(R.color.white_bg));
                break;
            case 1:

                binding.day2.setBackgroundResource(R.drawable.seleted_item_primary);
                binding.day2T1.setTextColor(getResources().getColor(R.color.white_bg));
                binding.day2T2.setTextColor(getResources().getColor(R.color.white_bg));
                break;
            case 2:

                binding.day3.setBackgroundResource(R.drawable.seleted_item_primary);
                binding.day31.setTextColor(getResources().getColor(R.color.white_bg));
                binding.day32.setTextColor(getResources().getColor(R.color.white_bg));
                break;
            case 3:

                binding.day4.setBackgroundResource(R.drawable.seleted_item_primary);
                binding.day41.setTextColor(getResources().getColor(R.color.white_bg));
                binding.day42.setTextColor(getResources().getColor(R.color.white_bg));
                break;
            case 4:

                binding.day5.setBackgroundResource(R.drawable.seleted_item_primary);
                binding.day51.setTextColor(getResources().getColor(R.color.white_bg));
                binding.day52.setTextColor(getResources().getColor(R.color.white_bg));
                break;
            case 5:

                binding.day6.setBackgroundResource(R.drawable.seleted_item_primary);
                binding.day61.setTextColor(getResources().getColor(R.color.white_bg));
                binding.day62.setTextColor(getResources().getColor(R.color.white_bg));
                break;
            case 6:

                binding.day7.setBackgroundResource(R.drawable.seleted_item_primary);
                binding.day71.setTextColor(getResources().getColor(R.color.white_bg));
                binding.day72.setTextColor(getResources().getColor(R.color.white_bg));
                break;
        }

    }

    // fetching list of reminders callback
    @Override
    public void onRemindersListFetched(List<ReminderResult> reminderResultList) {
        progressDialog.dismiss();

        if (reminderResultList != null && reminderResultList.size() > 0) {
            // reminders are present

            // updating global list of reminders
            if (reminderViewModel.selected_dow == 0){
                // only updating global list of reminders with current day's reminder list
                CaregiverMainViewModel.remindersList = reminderResultList;
            }

            binding.remindersRv.setVisibility(View.VISIBLE);
            binding.noData.setVisibility(View.GONE);

            reminderAdapter.submitLIst(reminderResultList);
        } else {
            binding.remindersRv.setVisibility(View.GONE);
            binding.noData.setVisibility(View.VISIBLE);
        }

    }

    @Override
    public void onFetchRemindersListFailed(Throwable t, String message) {
        progressDialog.dismiss();
        binding.remindersRv.setVisibility(View.GONE);
        binding.noData.setVisibility(View.VISIBLE);

        AppUtil.showAlert(requireContext(),
                getString(R.string.something_went_wrong),
                message,
                getString(R.string.ok),
                ((dialog, which) -> {
                    dialog.dismiss();
                }), null, null);
    }

    // delete reminder callback
    @Override
    public void onReminderDeleted(int adapterPos) {
        Toast.makeText(requireContext(), "Reminder deleted.", Toast.LENGTH_SHORT).show();
        progressDialog.dismiss();
        loadReminderList(weekDayViewsList.get(reminderViewModel.selected_dow).day_of_week);
    }

    @Override
    public void onReminderDeleteFailed(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);
    }

    // reminder clicked listener
    @Override
    public void onReminderClicked(ReminderResult reminderResult, int position) {
        editReminder(position);
    }

    // swipe option menu click listener for reminder list
    @Override
    public void onSwipeOptionClicked(int viewID, int position) {
        if (viewID == R.id.reminder_delete) {

            AppUtil.showSOSDecision(requireContext(),
                    getString(R.string.delete_med_reminder),
                    getString(R.string.yes), getString(R.string.no),
                    v -> {
                        // yes button clicked
                        int patientReminderId = reminderAdapter.getReminderResultList().get(position).id;
                        String token = "Bearer " + AppUtil.getPatientToken(requireContext());

                        progressDialog.setTitle("Please wait...");
                        progressDialog.setMessage("while we delete the reminder for you.");
                        progressDialog.setCancelable(false);
                        progressDialog.show();

                        reminderViewModel.deleteReminder(AppUtil.getPatientUid(requireContext()),
                                patientReminderId,
                                position,
                                token,
                                this);

                    }, v -> {
                        // no button clicked
                    });

        } else if (viewID == R.id.reminder_edit) {
            editReminder(position);
        }
    }

    private void editReminder(int position) {
        if (reminderAdapter == null) return;

        Bundle bundle = new Bundle();

        bundle.putSerializable(AddReminderFragment.REMINDER_KEY, reminderAdapter.getReminderResultList().get(position));

        try {
            Navigation.findNavController(binding.getRoot())
                    .navigate(R.id.action_reminderFragment_to_addReminderFragment, bundle);
        } catch (Exception e) {
            // there may be a IllegalStateException as this same fragment is used from another fragment
            // and not through the nav graph

            try {
                getParentFragmentManager().beginTransaction()
                        .replace(R.id.fcv_profile_shower, AddReminderFragment.class, bundle)
                        .addToBackStack("add_reminder")
                        .commitAllowingStateLoss();
            } catch (Exception ex) {
                // user may be out of context
            }
        }
    }

    @Override
    public void onReminderAdded(ReminderResult reminderDetails) {
        progressDialog.dismiss();
        loadReminderList(weekDayViewsList.get(reminderViewModel.selected_dow).day_of_week);
    }

    @Override
    public void onReminderAddFailed(Throwable t, String message) {
        progressDialog.dismiss();

        AppUtil.showAlert(requireContext(),
                getString(R.string.something_went_wrong),
                message,
                getString(R.string.yes),
                (dialog, which) -> {
                    dialog.dismiss();
                }, null, null);
    }

    @Override
    public void onCheck(ReminderResult reminderResult, int position) {
        // is user checking only today's check
        try {
            int today_date = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
            int selected_date = Integer.parseInt(weekDayViewsList.get(reminderViewModel.selected_dow).date.getText().toString());

            if (today_date == selected_date) {
                if (reminderResult.reminder_marked != null){
                    // already marked
                    // now checking if it is today user has marked it done
                    // if not, we shall allow them to mark it done for today

                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());

                    try {
                        Date routine_date = sdf.parse(reminderResult.reminder_marked);
                        if (routine_date == null) {
                            throw new Exception("Cannot parse routine marked date from Backend");
                        }

                        if (today_date == routine_date.getDate()){
                            // It is today when user has marked it done
                            // Thus, not allowing them to mark it done again

                            Toast.makeText(requireContext(), "Cannot be undone.", Toast.LENGTH_SHORT).show();
                            return;
                        }
                    }catch (Exception e){
                        // do nothing
                    }
                }

                AppUtil.showAlert(requireContext(),
                        "Please confirm that...",
                        "You have taken " + reminderResult.medicine_name + " medication",
                        getString(R.string.yes),
                        (dialog, which) -> {
                            dialog.dismiss();

                            updateRoutine(reminderResult, position);

                        }, getString(R.string.no),
                        (dialog, which) -> {
                            dialog.dismiss();
                        });
            } else {
                Toast.makeText(requireContext(), "Cannot mark future routine.", Toast.LENGTH_SHORT).show();
            }

        } catch (Exception e) {
            Toast.makeText(requireContext(), "Couldn't be done.", Toast.LENGTH_SHORT).show();
        }
    }

    private void updateRoutine(ReminderResult reminderResult, int position) {
        progressDialog.setTitle("Please wait...");
        progressDialog.setMessage("saving your reminder");
        progressDialog.setCancelable(false);
        progressDialog.show();

        Calendar current = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());

        reminderResult.patientRemainderId = reminderResult.id;
        reminderResult.reminder_marked = sdf.format(current.getTime());
        reminderResult.is_update = "1";

        // need to change date format as backend accepts dd-MM-yyyy
        // and responds as yyyy-dd-MM
        SimpleDateFormat date_f1 = new SimpleDateFormat("yyyy-dd-MM", Locale.getDefault());
        SimpleDateFormat date_f2 = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault());

        String refill_date;

        try {
            Date date = date_f1.parse(reminderResult.medication_refill_date);
            refill_date = date_f2.format(date);
        } catch (Exception e) {
            refill_date = date_f2.format(Calendar.getInstance().getTime());
        }

        reminderResult.medication_refill_date = refill_date;

        // to edit the reminder need to send  medicine_time_list
        reminderResult.medicine_time_list = new ArrayList<>();
        reminderResult.medicine_time_list.add(reminderResult.medicine_time);

        reminderViewModel.addReminder(
                AppUtil.getPatientUid(requireContext()),
                reminderResult,
                "Bearer " + AppUtil.getPatientToken(requireContext()),
                this
        );
    }
}
