package com.example.petstoremobile.fragments.listfragments;

import android.graphics.Color;
import android.os.Bundle;

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

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.petstoremobile.R;
import com.example.petstoremobile.adapters.AppointmentAdapter;
import com.example.petstoremobile.api.auth.TokenManager;
import com.example.petstoremobile.databinding.FragmentAppointmentBinding;
import com.example.petstoremobile.dtos.AppointmentDTO;
import com.example.petstoremobile.dtos.StoreDTO;
import com.example.petstoremobile.utils.BulkDeleteHandler;
import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.SpinnerUtils;
import com.example.petstoremobile.utils.UIUtils;
import com.example.petstoremobile.viewmodels.AppointmentListViewModel;
import com.example.petstoremobile.utils.EventDecorator;
import com.example.petstoremobile.viewmodels.AuthViewModel;
import com.prolificinteractive.materialcalendarview.CalendarDay;
import com.prolificinteractive.materialcalendarview.CalendarMode;

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

import javax.inject.Inject;

import dagger.hilt.android.AndroidEntryPoint;

@AndroidEntryPoint
public class AppointmentFragment extends Fragment implements AppointmentAdapter.OnAppointmentClickListener {

    private FragmentAppointmentBinding binding;
    private List<AppointmentDTO> appointmentList = new ArrayList<>();

    private AppointmentAdapter adapter;
    private AppointmentListViewModel viewModel;
    private AuthViewModel authViewModel;
    private BulkDeleteHandler bulkDeleteHandler;

    @Inject TokenManager tokenManager;

    private CalendarDay selectedCalendarDay;
    private boolean isMonthMode = false;
    private Long currentUserId = null;
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel = new ViewModelProvider(this).get(AppointmentListViewModel.class);
        authViewModel = new ViewModelProvider(this).get(AuthViewModel.class);
    }

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

        setupRecyclerView();
        setupSearch();
        setupStatusFilter();
        setupStoreFilter();
        setupSwipeRefresh();
        setupCalendar();
        setupFilterToggle();
        setupMyAppointmentFilter();
        setupBulkDelete();
        observeViewModel();

        binding.fabAddAppointment.setOnClickListener(v -> openAppointmentDetails(-1));

        UIUtils.setupHamburgerMenu(binding.btnHamburger, this);

        binding.btnToggleCalendarMode.setOnClickListener(v -> toggleCalendarMode());

        loadCurrentUserInfo();

        return binding.getRoot();
    }

    private void observeViewModel() {
        viewModel.getAppointments().observe(getViewLifecycleOwner(), list -> {
            appointmentList.clear();
            appointmentList.addAll(list);
            updateCalendarDecorators();
            adapter.notifyDataSetChanged();
        });

        viewModel.getStores().observe(getViewLifecycleOwner(), list -> {
            SpinnerUtils.populateWhiteSpinner(requireContext(), binding.spinnerStore, list,
                    StoreDTO::getStoreName, "All Stores", -1L, StoreDTO::getStoreId);
        });

        viewModel.getIsLoading().observe(getViewLifecycleOwner(), loading -> {
            binding.swipeRefreshAppointment.setRefreshing(loading);
        });
    }

    private void setupBulkDelete() {
        bulkDeleteHandler = new BulkDeleteHandler(
                this,
                binding.layoutBulkDelete,
                binding.tvSelectionCount,
                binding.btnBulkDelete,
                adapter,
                "appointment",
                viewModel::bulkDeleteAppointments,
                () -> loadAppointmentData(true)
        );
    }

    @Override
    public void onResume() {
        super.onResume();
        loadAppointmentData(true);
        if (!isStaff()) viewModel.loadStores();
    }

    private void toggleCalendarMode() {
        isMonthMode = !isMonthMode;
        binding.calendarView.state().edit()
                .setCalendarDisplayMode(isMonthMode ? CalendarMode.MONTHS : CalendarMode.WEEKS)
                .commit();
    }

    private void setupMyAppointmentFilter() {
        binding.btnMyAppointments.setOnClickListener(v -> {
            loadAppointmentData(true);
        });
    }

    private void loadCurrentUserInfo() {
        authViewModel.getMe().observe(getViewLifecycleOwner(), resource -> {
            if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
                currentUserId = resource.data.getId();
            }
        });
    }

    private void setupFilterToggle() {
        if (isStaff()) {
            UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchAppointment, binding.spinnerStatus);
            binding.spinnerStore.setVisibility(View.GONE);
        } else {
            UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchAppointment,
                    binding.spinnerStatus, binding.spinnerStore);
        }
    }

    private void setupCalendar() {
        binding.calendarView.setOnDateChangedListener((widget, date, selected) -> {
            if (selected) {
                if (date.equals(selectedCalendarDay)) {
                    selectedCalendarDay = null;
                    binding.calendarView.clearSelection();
                } else {
                    selectedCalendarDay = date;
                }
            } else {
                selectedCalendarDay = null;
            }
            loadAppointmentData(true);
        });
    }

    private void updateCalendarDecorators() {
        HashSet<CalendarDay> datesWithAppointments = new HashSet<>();
        for (AppointmentDTO appointment : appointmentList) {
            try {
                Date date = dateFormat.parse(appointment.getAppointmentDate());
                if (date != null) {
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(date);
                    datesWithAppointments.add(CalendarDay.from(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH)));
                }
            } catch (ParseException e) {
                Log.e("AppointmentFragment", "Error parsing date: " + appointment.getAppointmentDate());
            }
        }
        binding.calendarView.removeDecorators();
        binding.calendarView.addDecorator(new EventDecorator(Color.RED, datesWithAppointments));
    }

    private void setupSearch() {
        UIUtils.attachSearch(binding.etSearchAppointment, () -> loadAppointmentData(true));
    }

    private void setupStatusFilter() {
        String[] statuses = {"All Statuses", "Booked", "Completed", "Cancelled", "Missed"};
        SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerStatus, statuses, () -> loadAppointmentData(true));
    }

    private void setupStoreFilter() {
        SpinnerUtils.setupFilterSpinner(binding.spinnerStore, () -> loadAppointmentData(true));
    }

    private void setupSwipeRefresh() {
        binding.swipeRefreshAppointment.setOnRefreshListener(() -> loadAppointmentData(true));
    }

    private void openAppointmentDetails(int position) {
        Bundle args = new Bundle();
        if (position != -1) {
            AppointmentDTO a = appointmentList.get(position);
            args.putLong("appointmentId", a.getAppointmentId());
        }
        NavHostFragment.findNavController(this).navigate(R.id.nav_appointment_detail, args);
    }

    @Override
    public void onAppointmentClick(int position) {
        openAppointmentDetails(position);
    }

    @Override
    public void onSelectionChanged(int count) {
        if (bulkDeleteHandler != null) {
            bulkDeleteHandler.onSelectionChanged(count);
        }
    }

    private boolean isStaff() {
        return "STAFF".equalsIgnoreCase(tokenManager.getRole());
    }

    private void loadAppointmentData(boolean reset) {
        String query = binding.etSearchAppointment.getText().toString().trim();
        String status = binding.spinnerStatus.getSelectedItem() != null ? binding.spinnerStatus.getSelectedItem().toString() : "All Statuses";

        Long storeId;
        if (isStaff()) {
            storeId = tokenManager.getPrimaryStoreId();
        } else {
            storeId = null;
            List<StoreDTO> stores = viewModel.getStores().getValue();
            if (binding.spinnerStore.getSelectedItemPosition() > 0 && stores != null && !stores.isEmpty()) {
                storeId = stores.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId();
            }
        }

        String selectedDateString = null;
        if (selectedCalendarDay != null) {
            selectedDateString = String.format(Locale.getDefault(), "%04d-%02d-%02d",
                    selectedCalendarDay.getYear(), selectedCalendarDay.getMonth(), selectedCalendarDay.getDay());
        }

        Long employeeId = null;
        if (binding.btnMyAppointments.isChecked()) {
            employeeId = currentUserId;
        }

        if (status.equals("All Statuses")) status = null;
        else status = status.toUpperCase();

        viewModel.loadAppointments(reset, query, status, storeId, selectedDateString, employeeId);
    }

    private void setupRecyclerView() {
        adapter = new AppointmentAdapter(appointmentList, this);
        binding.recyclerViewAppointments.setLayoutManager(new LinearLayoutManager(getContext()));
        binding.recyclerViewAppointments.setAdapter(adapter);

        binding.recyclerViewAppointments.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                if (dy <= 0) return;
                LinearLayoutManager lm = (LinearLayoutManager) binding.recyclerViewAppointments.getLayoutManager();
                if (lm == null) return;
                int visible = lm.getChildCount();
                int total = lm.getItemCount();
                int firstVis = lm.findFirstVisibleItemPosition();
                Boolean isLoading = viewModel.getIsLoading().getValue();
                if ((isLoading == null || !isLoading) && !viewModel.isLastPage() && (visible + firstVis) >= total - 3) {
                    loadAppointmentData(false);
                }
            }
        });
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}
