package com.example.petstoremobile.viewmodels;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.example.petstoremobile.dtos.AdoptionDTO;
import com.example.petstoremobile.dtos.DropdownDTO;
import com.example.petstoremobile.repositories.AdoptionRepository;
import com.example.petstoremobile.repositories.CustomerRepository;
import com.example.petstoremobile.repositories.PetRepository;
import com.example.petstoremobile.repositories.StoreRepository;
import com.example.petstoremobile.utils.DateTimeUtils;
import com.example.petstoremobile.utils.Resource;

import androidx.lifecycle.Observer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import javax.inject.Inject;

import dagger.hilt.android.lifecycle.HiltViewModel;

@HiltViewModel
public class AdoptionDetailViewModel extends ViewModel {
    private final AdoptionRepository adoptionRepository;
    private final PetRepository petRepository;
    private final CustomerRepository customerRepository;
    private final StoreRepository storeRepository;

    private long adoptionId = -1;

    private final MutableLiveData<List<DropdownDTO>> petList = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<DropdownDTO>> customerList = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<DropdownDTO>> storeList = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<DropdownDTO>> employeeList = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<ViewState> viewState = new MutableLiveData<>(new ViewState());

    @Inject
    public AdoptionDetailViewModel(AdoptionRepository adoptionRepository, PetRepository petRepository,
                                   CustomerRepository customerRepository, StoreRepository storeRepository) {
        this.adoptionRepository = adoptionRepository;
        this.petRepository = petRepository;
        this.customerRepository = customerRepository;
        this.storeRepository = storeRepository;
    }

    public void setAdoptionId(long id) {
        this.adoptionId = id;
        initMode(id != -1);
    }

    public long getAdoptionId() {
        return adoptionId;
    }

    public boolean isEditing() {
        ViewState current = viewState.getValue();
        return current != null && current.isEditing;
    }

    public LiveData<ViewState> getViewState() {
        return viewState;
    }

    public void initMode(boolean isEditing) {
        updateViewState(state -> {
            state.isEditing = isEditing;
            state.modeTitle = isEditing ? "Edit Adoption" : "Add Adoption";
            state.saveButtonText = isEditing ? "Save" : "Add";
            state.isAdoptionIdVisible = isEditing;
            state.isDeleteVisible = isEditing;
            state.isFeeEnabled = false;
            if (!isEditing) {
                state.isCustomerEnabled = true;
                state.isStoreEnabled = true;
                state.isPetEnabled = false;
                state.isEmployeeEnabled = false;
                state.isDateEnabled = true;
                state.isStatusEnabled = true;
                state.availableStatuses = new String[]{"Pending"};
                state.selectedStatus = "Pending";
            } else {
                state.isCustomerEnabled = false;
                state.isStoreEnabled = false;
                state.isPetEnabled = false;
                state.isEmployeeEnabled = false;
                state.isDateEnabled = false;
                state.isStatusEnabled = false;
            }
        });
    }

    public void loadInitialFormData(boolean isEditing) {
        // Pets are loaded dynamically based on store selection; no pre-load needed.
        observeOnce(customerRepository.getCustomerDropdowns(), r -> {
            if (r != null && r.status == Resource.Status.SUCCESS && r.data != null) {
                customerList.setValue(r.data);
            }
        });
        observeOnce(storeRepository.getStoreDropdowns(), r -> {
            if (r != null && r.status == Resource.Status.SUCCESS && r.data != null) {
                storeList.setValue(r.data);
            }
        });
    }

    public void onCustomerSelected(int position) {
        List<DropdownDTO> list = customerList.getValue();
        Long customerId = (position > 0 && list != null && position <= list.size())
                ? list.get(position - 1).getId() : null;
        updateViewState(state -> state.selectedCustomerId = customerId);
    }

    public void onStoreSelected(int position) {
        List<DropdownDTO> list = storeList.getValue();
        if (position > 0 && list != null && position <= list.size()) {
            Long storeId = list.get(position - 1).getId();
            updateViewState(state -> {
                state.selectedStoreId = storeId;
                if (!state.isCancelled && !state.isEditing) {
                    state.isEmployeeEnabled = true;
                    state.isPetEnabled = true;
                }
            });
            loadEmployeesForStore(storeId);
            if (!isEditing()) loadAvailablePetsByStore(storeId);
        } else {
            employeeList.setValue(new ArrayList<>());
            petList.setValue(new ArrayList<>());
            updateViewState(state -> {
                state.selectedStoreId = null;
                state.selectedEmployeeId = null;
                state.selectedPetId = null;
                state.isEmployeeEnabled = false;
                state.isPetEnabled = false;
            });
        }
    }

    public void onPetSelected(int position) {
        List<DropdownDTO> list = petList.getValue();
        if (position > 0 && list != null && position <= list.size()) {
            Long petId = list.get(position - 1).getId();
            updateViewState(s -> s.selectedPetId = petId);
            loadPetPrice(petId);
        } else {
            updateViewState(s -> {
                s.selectedPetId = null;
                s.adoptionFee = "";
            });
        }
    }

    private void loadAvailablePetsByStore(Long storeId) {
        observeOnce(petRepository.getAdoptionPets(storeId), r -> {
            if (r != null && r.status == Resource.Status.SUCCESS && r.data != null) {
                petList.setValue(r.data);
            }
        });
    }

    private void loadPetPrice(Long petId) {
        observeOnce(petRepository.getPetById(petId), r -> {
            if (r != null && r.status == Resource.Status.SUCCESS && r.data != null) {
                com.example.petstoremobile.dtos.PetDTO pet = r.data;
                // In edit mode, add the pet to the list so the spinner can display its name
                if (isEditing()) {
                    List<DropdownDTO> single = new ArrayList<>();
                    single.add(new DropdownDTO(pet.getPetId(), pet.getPetName()));
                    petList.setValue(single);
                }
                if (pet.getPetPrice() != null) {
                    String price = String.format(Locale.getDefault(), "%.2f", pet.getPetPrice());
                    updateViewState(s -> s.adoptionFee = price);
                }
            }
        });
    }

    private void loadEmployeesForStore(Long storeId) {
        observeOnce(storeRepository.getStoreEmployees(storeId), r -> {
            if (r != null && r.status == Resource.Status.SUCCESS && r.data != null) {
                employeeList.setValue(r.data);
            }
        });
    }

    /**
     * Called when the date or status changes in the UI. Applies date-based field enabling.
     */
    public void onDateChanged(String date, String currentStatus) {
        updateViewState(s -> {
            if (s.isCancelled) return;
            s.availableStatuses = calculateAvailableStatuses(s.isEditing, date);
            List<String> available = Arrays.asList(s.availableStatuses);
            if (!currentStatus.isEmpty() && available.contains(currentStatus)) {
                s.selectedStatus = currentStatus;
            } else if (!available.contains(s.selectedStatus) && s.availableStatuses.length > 0) {
                s.selectedStatus = s.availableStatuses[0];
            }

            if (!s.isEditing) return; // add mode: field enabling handled separately

            boolean isPast = DateTimeUtils.isDateBeforeToday(date);
            if (isPast) {
                setAllEditableFieldsEnabled(s, false);
                s.isStatusEnabled = true;
            } else if (!date.isEmpty()) {
                setAllEditableFieldsEnabled(s, false);
                s.isEmployeeEnabled = true;
                s.isDateEnabled = true;
                s.isStatusEnabled = true;
            } else {
                // Date cleared: disable everything except the date field so user can pick again
                setAllEditableFieldsEnabled(s, false);
                s.isDateEnabled = true;
            }
        });
    }

    private String[] calculateAvailableStatuses(boolean isEditing, String date) {
        if (!isEditing) return new String[]{"Pending"};
        if (date == null || date.isEmpty()) return new String[]{};
        if (DateTimeUtils.isDateBeforeToday(date)) return new String[]{"Completed", "Missed"};
        return new String[]{"Pending", "Cancelled"};
    }

    /** Disables all editable fields (fee is always disabled separately). */
    private void setAllEditableFieldsEnabled(ViewState s, boolean enabled) {
        s.isCustomerEnabled = enabled;
        s.isStoreEnabled = enabled;
        s.isPetEnabled = enabled;
        s.isEmployeeEnabled = enabled;
        s.isDateEnabled = enabled;
        // fee never editable
    }

    public LiveData<Resource<AdoptionDTO>> loadAdoption() {
        MutableLiveData<Resource<AdoptionDTO>> result = new MutableLiveData<>();
        observeOnce(adoptionRepository.getAdoptionById(adoptionId), resource -> {
            if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) {
                AdoptionDTO a = resource.data;
                String formattedStatus = DateTimeUtils.formatStatusFromBackend(
                        a.getAdoptionStatus() != null ? a.getAdoptionStatus() : "");
                String adoptionDate = a.getAdoptionDate() != null ? a.getAdoptionDate() : "";

                updateViewState(state -> {
                    state.selectedPetId = a.getPetId();
                    state.selectedCustomerId = a.getCustomerId();
                    state.selectedStoreId = a.getSourceStoreId();
                    state.selectedEmployeeId = a.getEmployeeId();
                    state.adoptionDate = adoptionDate;
                    state.adoptionFee = a.getAdoptionFee() != null ? a.getAdoptionFee().toPlainString() : "";
                    state.selectedStatus = formattedStatus;
                    state.adoptionStatus = formattedStatus;

                    if ("Cancelled".equalsIgnoreCase(formattedStatus)) {
                        state.isCancelled = true;
                        state.isCustomerEnabled = false;
                        state.isStoreEnabled = false;
                        state.isPetEnabled = false;
                        state.isEmployeeEnabled = false;
                        state.isStatusEnabled = false;
                        state.isDateEnabled = false;
                        state.isFeeEnabled = false;
                        state.isSaveVisible = false;
                        state.availableStatuses = new String[]{"Cancelled"};
                    } else {
                        state.availableStatuses = calculateAvailableStatuses(true, adoptionDate);
                        boolean isPast = DateTimeUtils.isDateBeforeToday(adoptionDate);
                        if (isPast) {
                            setAllEditableFieldsEnabled(state, false);
                            state.isStatusEnabled = true;
                        } else if (!adoptionDate.isEmpty()) {
                            setAllEditableFieldsEnabled(state, false);
                            state.isEmployeeEnabled = true;
                            state.isDateEnabled = true;
                            state.isStatusEnabled = true;
                        }
                    }
                });

                if (a.getSourceStoreId() != null) loadEmployeesForStore(a.getSourceStoreId());
                if (a.getPetId() != null) loadPetPrice(a.getPetId());
            }
            result.setValue(resource);
        });
        return result;
    }

    public LiveData<Resource<AdoptionDTO>> saveAdoption(AdoptionDTO dto) {
        if (isEditing()) {
            return adoptionRepository.updateAdoption(adoptionId, dto);
        }
        return adoptionRepository.createAdoption(dto);
    }

    public LiveData<Resource<Void>> deleteAdoption() {
        return adoptionRepository.deleteAdoption(adoptionId);
    }

    public LiveData<List<DropdownDTO>> getPetList() { return petList; }
    public LiveData<List<DropdownDTO>> getCustomerList() { return customerList; }
    public LiveData<List<DropdownDTO>> getStoreList() { return storeList; }
    public LiveData<List<DropdownDTO>> getEmployeeList() { return employeeList; }

    public void setEmployeeList(List<DropdownDTO> list) { employeeList.setValue(list); }

    private void updateViewState(Action<ViewState> action) {
        ViewState current = viewState.getValue();
        if (current != null) {
            action.run(current);
            viewState.setValue(current);
        }
    }

    private interface Action<T> {
        void run(T target);
    }

    /**
     * Observes a LiveData once, removing the observer after the first response.
     * */
    private <T> void observeOnce(LiveData<Resource<T>> liveData, Observer<Resource<T>> handler) {
        liveData.observeForever(new Observer<Resource<T>>() {
            @Override
            public void onChanged(Resource<T> resource) {
                if (resource == null || resource.status != Resource.Status.LOADING) {
                    liveData.removeObserver(this);
                }
                handler.onChanged(resource);
            }
        });
    }

    public static class ViewState {
        public boolean isEditing = false;
        public boolean isAdoptionIdVisible = false;
        public boolean isDeleteVisible = false;
        public boolean isCancelled = false;
        public boolean isPetEnabled = false;
        public boolean isEmployeeEnabled = false;
        public boolean isCustomerEnabled = true;
        public boolean isStoreEnabled = true;
        public boolean isStatusEnabled = true;
        public boolean isDateEnabled = true;
        public boolean isFeeEnabled = false; // always read-only
        public boolean isSaveVisible = true;
        public String[] availableStatuses = new String[]{};
        public String selectedStatus = "";
        public String modeTitle = "Add Adoption";
        public String saveButtonText = "Add";
        public Long selectedPetId = null;
        public Long selectedCustomerId = null;
        public Long selectedStoreId = null;
        public Long selectedEmployeeId = null;
        public String adoptionDate = "";
        public String adoptionFee = "";
        public String adoptionStatus = "";
    }
}
