package com.app.simplitend.patientprofile.setuproutine;

import static com.app.simplitend.patientprofile.setuproutine.AddRoutineFragment.ROUTINE_KEY;

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.RoutineFragmentBinding;
import com.app.simplitend.patientprofile.ProfileContracts;
import com.app.simplitend.patientprofile.medreminder.WeekDayViewHolder;
import com.app.simplitend.patientprofile.setuproutine.mvvm.RoutineAdapter;
import com.app.simplitend.patientprofile.setuproutine.mvvm.RoutineDetails;
import com.app.simplitend.patientprofile.setuproutine.mvvm.RoutineViewModel;

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 RoutineFragment extends Fragment implements RoutineAdapter.ClickListener,
        RoutineAdapter.DeleteClickListener,
        RoutineAdapter.CheckClickListener,
        ProfileContracts.GetRoutinesCallback,
        ProfileContracts.RoutineDeleteCallback,
        ProfileContracts.AddNUpdateRoutineCallback {

    private static final String TAG = "RoutineFragment";

    // view binding
    protected RoutineFragmentBinding binding;

    private RoutineAdapter routineAdapter;

    private ArrayList<WeekDayViewHolder> weekDayViewsList;

    private RoutineViewModel routineViewModel;

    private ProgressDialog progressDialog;

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

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

        initViews();

        clickEvents();

        return binding.getRoot();
    }

    private void clickEvents() {

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

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

        binding.addRoutine.setOnClickListener(v -> {
            try {

                Navigation.findNavController(v).navigate(R.id.action_routineFragment_to_addRoutineFragment);
            } 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, AddRoutineFragment.class, null)
                            .addToBackStack("add_reminder")
                            .commitAllowingStateLoss();
                } catch (Exception ex) {
                    // user may be out of context
                }
            }
        });

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

    }

    private void loadRoutineList(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());
        routineViewModel.getRoutines(patient_uid, token, day_of_week, this);

    }

    private void initViews() {
        progressDialog = new ProgressDialog(requireContext());

        binding.routineRv.setLayoutManager(new LinearLayoutManager(requireContext()));
        routineAdapter = new RoutineAdapter();
        routineAdapter.setDeleteClickListener(this);
        routineAdapter.setClickListener(this);
        routineAdapter.setCheckClickListener(this);
        binding.routineRv.setAdapter(routineAdapter);

        Calendar calendar = Calendar.getInstance();

        String today_date = routineViewModel.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(routineViewModel.selected_dow = 0);

        loadRoutineList(weekDayViewsList.get(routineViewModel.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(routineViewModel.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 setDayOfWeek(int selection) {

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

        clearSelection();

        switch (routineViewModel.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;
        }

    }

    private void clearSelection() {
        switch (routineViewModel.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;
        }
    }

    // delete routine callback


    @Override
    public void onRoutineDeleted(int adapterPosition) {
        Toast.makeText(requireContext(), "Reminder deleted.", Toast.LENGTH_SHORT).show();
        progressDialog.dismiss();
        loadRoutineList(weekDayViewsList.get(routineViewModel.selected_dow).day_of_week);
    }

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

    // get routine callback
    @Override
    public void onRoutinesFetched(List<RoutineDetails> routineList) {
        progressDialog.dismiss();

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

            // updating global list of activities for today's day
            if (routineViewModel.selected_dow == 0) {
                CaregiverMainViewModel.activityList = routineList;
            }

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

            routineAdapter.submitList(routineList);
        } else {
            binding.routineRv.setVisibility(View.GONE);
            binding.noData.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onRoutinesFetchedFailed(Throwable t, String message) {
        progressDialog.dismiss();
        binding.routineRv.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);
    }

    @Override
    public void onDelete(RoutineDetails routine, int position) {

        AppUtil.showSOSDecision(requireContext(), getString(R.string.delete_med_routine),
                getString(R.string.yes), getString(R.string.no),
                v1 -> {
                    // yes click
                    progressDialog.setTitle("Please wait...");
                    progressDialog.setMessage("while we delete the routine for you.");
                    progressDialog.setCancelable(false);
                    progressDialog.show();

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

                    routineViewModel.deleteRoutine(AppUtil.getPatientUid(requireContext()),
                            routine.id,
                            position,
                            token,
                            this);
                }, v2 -> {
                    // no click
                });

    }

    @Override
    public void onClick(RoutineDetails routine, int position) {
        Bundle bundle = new Bundle();
        bundle.putSerializable(ROUTINE_KEY, routine);

        try {
            Navigation.findNavController(binding.getRoot()).navigate(R.id.action_routineFragment_to_addRoutineFragment, 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, AddRoutineFragment.class, bundle)
                        .addToBackStack("add_reminder")
                        .commitAllowingStateLoss();
            } catch (Exception ex) {
                // user may be out of context
            }
        }
    }

    @Override
    public void onCheckClick(RoutineDetails routineDetails, int position) {
        // is user checking only today's check
            /*
                now, we don't want to allow checking of routine of other day
             */
        try {
            int today_date = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
            int selected_date = Integer.parseInt(weekDayViewsList.get(routineViewModel.selected_dow).date.getText().toString());

            if (today_date == selected_date) {
                if (routineDetails.routine_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(routineDetails.routine_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(),
                        "Are you sure?",
                        "Do yuo want to check this routine?\nThis cannot be undone.",
                        getString(R.string.yes),
                        (dialog, which) -> {
                            dialog.dismiss();

                            updateRoutine(routineDetails, 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(RoutineDetails routine, int position) {

        progressDialog.setTitle("Please wait...");
        progressDialog.setMessage("saving your routine");
        progressDialog.setCancelable(false);
        progressDialog.show();

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

        routine.patientRoutineId = routine.id;
        routine.routine_marked = sdf.format(current.getTime());
        routine.is_update = 1;

        routineViewModel.addNUpdateRoutine(
                AppUtil.getPatientUid(requireContext()),
                routine,
                "Bearer " + AppUtil.getPatientToken(requireContext()),
                this
        );

    }

    @Override
    public void onRoutineAdded(RoutineDetails medicationInfo) {
        progressDialog.dismiss();
        loadRoutineList(weekDayViewsList.get(routineViewModel.selected_dow).day_of_week);
    }

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

    }
}
