package com.example.petstoremobile.fragments.listfragments.detailfragments;

import android.os.Bundle;
import android.view.*;
import android.widget.*;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment;

import com.example.petstoremobile.databinding.FragmentAdoptionDetailBinding;
import com.example.petstoremobile.dtos.*;
import com.example.petstoremobile.utils.DateTimeUtils;
import com.example.petstoremobile.utils.DialogUtils;
import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.SpinnerUtils;
import com.example.petstoremobile.utils.UIUtils;
import com.example.petstoremobile.api.auth.TokenManager;
import com.example.petstoremobile.viewmodels.AdoptionDetailViewModel;

import java.math.BigDecimal;
import java.util.*;

import javax.inject.Inject;

import dagger.hilt.android.AndroidEntryPoint;

/**
 * Fragment for displaying and editing adoption request details.
 */
@AndroidEntryPoint
public class AdoptionDetailFragment extends Fragment {

    private FragmentAdoptionDetailBinding binding;
    private AdoptionDetailViewModel viewModel;
    private boolean isUpdatingUI = false;

    @Inject TokenManager tokenManager;

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

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

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        setupSpinners();
        setupDatePicker();
        observeViewModel();
        Bundle args = getArguments();
        boolean isEditing = args != null && args.containsKey("adoptionId");
        viewModel.loadInitialFormData(isEditing);
        handleArguments();

        binding.btnAdoptionBack.setOnClickListener(v -> navigateBack());
        binding.btnSaveAdoption.setOnClickListener(v -> saveAdoption());
        binding.btnDeleteAdoption.setOnClickListener(v -> confirmDelete());
    }

    private void observeViewModel() {
        viewModel.getViewState().observe(getViewLifecycleOwner(), this::applyViewState);

        viewModel.getPetList().observe(getViewLifecycleOwner(), list -> {
            AdoptionDetailViewModel.ViewState state = viewModel.getViewState().getValue();
            Long petId = state != null ? state.selectedPetId : null;
            isUpdatingUI = true;
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionPet, list,
                    DropdownDTO::getLabel, "-- Select Pet --", petId, DropdownDTO::getId);
            isUpdatingUI = false;
        });

        viewModel.getCustomerList().observe(getViewLifecycleOwner(), list -> {
            AdoptionDetailViewModel.ViewState state = viewModel.getViewState().getValue();
            Long customerId = state != null ? state.selectedCustomerId : null;
            isUpdatingUI = true;
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionCustomer, list,
                    DropdownDTO::getLabel, "-- Select Customer --", customerId, DropdownDTO::getId);
            isUpdatingUI = false;
        });

        viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> {
            AdoptionDetailViewModel.ViewState state = viewModel.getViewState().getValue();
            Long storeId = isStaff() ? tokenManager.getPrimaryStoreId() : (state != null ? state.selectedStoreId : null);
            isUpdatingUI = true;
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionStore, list,
                    DropdownDTO::getLabel, "-- Select Store --", storeId, DropdownDTO::getId);
            isUpdatingUI = false;

            if (isStaff() && storeId != null) {
                int position = binding.spinnerAdoptionStore.getSelectedItemPosition();
                if (position > 0) viewModel.onStoreSelected(position);
            }
        });

        viewModel.getEmployeeList().observe(getViewLifecycleOwner(), list -> {
            AdoptionDetailViewModel.ViewState state = viewModel.getViewState().getValue();
            Long employeeId = state != null ? state.selectedEmployeeId : null;
            isUpdatingUI = true;
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionEmployee, list,
                    DropdownDTO::getLabel, "-- Select Staff --", employeeId, DropdownDTO::getId);
            isUpdatingUI = false;
        });
    }

    private void setLoading(boolean loading) {
        if (binding != null) {
            binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE);
        }
    }

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

    private void setupSpinners() {
        SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerAdoptionStatus, new String[]{});

        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerAdoptionCustomer, p -> {
            if (isUpdatingUI) return;
            viewModel.onCustomerSelected(p);
        });
        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerAdoptionStore, p -> {
            if (isUpdatingUI) return;
            viewModel.onStoreSelected(p);
        });

        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerAdoptionPet, p -> viewModel.onPetSelected(p));
        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerAdoptionStatus, p -> notifyDateStatusChange());
    }

    private void setupDatePicker() {
        binding.etAdoptionDate.setOnClickListener(v ->
                UIUtils.showDatePicker(requireContext(), binding.etAdoptionDate, this::notifyDateStatusChange));
    }

    private void notifyDateStatusChange() {
        if (isUpdatingUI) return;
        String date = binding.etAdoptionDate.getText().toString();
        Object selected = binding.spinnerAdoptionStatus.getSelectedItem();
        String status = selected != null ? selected.toString() : "";
        viewModel.onDateChanged(date, status);
    }

    private void handleArguments() {
        Bundle a = getArguments();
        if (a != null && a.containsKey("adoptionId")) {
            viewModel.setAdoptionId(a.getLong("adoptionId"));
            loadAdoptionData();
            return;
        }
        viewModel.setAdoptionId(-1);
    }

    private void loadAdoptionData() {
        viewModel.loadAdoption().observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.ERROR) {
                Toast.makeText(getContext(), "Failed to load adoption: " + resource.message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void applyViewState(AdoptionDetailViewModel.ViewState state) {
        isUpdatingUI = true;

        binding.tvAdoptionMode.setText(state.modeTitle);
        binding.tvAdoptionId.setText(DateTimeUtils.formatId(viewModel.getAdoptionId()));
        binding.tvAdoptionId.setVisibility(state.isAdoptionIdVisible ? View.VISIBLE : View.GONE);
        binding.btnDeleteAdoption.setVisibility(state.isDeleteVisible ? View.VISIBLE : View.GONE);
        binding.btnSaveAdoption.setText(state.saveButtonText);
        binding.btnSaveAdoption.setVisibility(state.isSaveVisible ? View.VISIBLE : View.GONE);

        UIUtils.setViewsEnabled(state.isCustomerEnabled, binding.spinnerAdoptionCustomer);
        UIUtils.setViewsEnabled(state.isPetEnabled, binding.spinnerAdoptionPet);
        UIUtils.setViewsEnabled(state.isStoreEnabled, binding.spinnerAdoptionStore);
        UIUtils.setViewsEnabled(state.isEmployeeEnabled, binding.spinnerAdoptionEmployee);
        UIUtils.setViewsEnabled(state.isDateEnabled, binding.etAdoptionDate);
        UIUtils.setViewsEnabled(state.isFeeEnabled, binding.etAdoptionFee);
        UIUtils.setViewsEnabled(state.isStatusEnabled, binding.spinnerAdoptionStatus);

        SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerAdoptionStatus, state.availableStatuses);
        SpinnerUtils.setSelectionByValue(binding.spinnerAdoptionStatus, state.selectedStatus);

        if (!state.adoptionDate.isEmpty()) {
            binding.etAdoptionDate.setText(state.adoptionDate);
        }
        if (!state.adoptionFee.isEmpty()) {
            binding.etAdoptionFee.setText(state.adoptionFee);
        }

        // Re-populate spinners with updated preselected IDs
        List<DropdownDTO> pets = viewModel.getPetList().getValue();
        if (pets != null) SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionPet,
                pets, DropdownDTO::getLabel, "-- Select Pet --", state.selectedPetId, DropdownDTO::getId);

        List<DropdownDTO> customers = viewModel.getCustomerList().getValue();
        if (customers != null) SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionCustomer,
                customers, DropdownDTO::getLabel, "-- Select Customer --", state.selectedCustomerId, DropdownDTO::getId);

        List<DropdownDTO> stores = viewModel.getStoreList().getValue();
        if (stores != null) SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionStore,
                stores, DropdownDTO::getLabel, "-- Select Store --", state.selectedStoreId, DropdownDTO::getId);

        List<DropdownDTO> employees = viewModel.getEmployeeList().getValue();
        if (employees != null) SpinnerUtils.populateSpinner(requireContext(), binding.spinnerAdoptionEmployee,
                employees, DropdownDTO::getLabel, "-- Select Staff --", state.selectedEmployeeId, DropdownDTO::getId);

        if (isStaff()) UIUtils.setViewsEnabled(false, binding.spinnerAdoptionStore);

        isUpdatingUI = false;
    }

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

    private void saveAdoption() {
        if (!InputValidator.isSpinnerSelected(binding.spinnerAdoptionCustomer, "Customer")) return;
        if (!InputValidator.isSpinnerSelected(binding.spinnerAdoptionPet, "Pet")) return;
        if (!InputValidator.isSpinnerSelected(binding.spinnerAdoptionStore, "Store")) return;
        if (!InputValidator.isNotEmpty(binding.etAdoptionDate, "Adoption Date")) return;

        BigDecimal fee = BigDecimal.ZERO;
        String feeStr = binding.etAdoptionFee.getText().toString().trim();
        if (!feeStr.isEmpty()) {
            try { fee = new BigDecimal(feeStr); } catch (NumberFormatException ignored) {}
        }

        List<DropdownDTO> customerListVal  = viewModel.getCustomerList().getValue();
        List<DropdownDTO> petListVal       = viewModel.getPetList().getValue();
        List<DropdownDTO> storeListVal     = viewModel.getStoreList().getValue();
        if (customerListVal == null || petListVal == null || storeListVal == null) {
            Toast.makeText(getContext(), "Data not loaded yet, please try again", Toast.LENGTH_SHORT).show();
            return;
        }
        DropdownDTO customer = customerListVal.get(binding.spinnerAdoptionCustomer.getSelectedItemPosition() - 1);
        DropdownDTO pet      = petListVal.get(binding.spinnerAdoptionPet.getSelectedItemPosition() - 1);
        DropdownDTO store    = storeListVal.get(binding.spinnerAdoptionStore.getSelectedItemPosition() - 1);

        Long employeeId = null;
        if (binding.spinnerAdoptionEmployee.getSelectedItemPosition() > 0 && viewModel.getEmployeeList().getValue() != null) {
            employeeId = viewModel.getEmployeeList().getValue().get(binding.spinnerAdoptionEmployee.getSelectedItemPosition() - 1).getId();
        }

        String adoptionDate = binding.etAdoptionDate.getText().toString().trim();
        Object selectedStatus = binding.spinnerAdoptionStatus.getSelectedItem();
        String status = selectedStatus != null ? selectedStatus.toString().toUpperCase() : "";

        AdoptionDTO dto = new AdoptionDTO(
                pet.getId(), customer.getId(), employeeId, store.getId(), adoptionDate, status, fee);

        viewModel.saveAdoption(dto).observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.SUCCESS) {
                Toast.makeText(getContext(), viewModel.isEditing() ? "Updated" : "Saved", Toast.LENGTH_SHORT).show();
                navigateBack();
            } else if (resource.status == Resource.Status.ERROR) {
                Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void confirmDelete() {
        DialogUtils.showDeleteConfirmDialog(requireContext(), "Adoption Record", () ->
                viewModel.deleteAdoption().observe(getViewLifecycleOwner(), resource -> {
                    if (resource == null) return;
                    setLoading(resource.status == Resource.Status.LOADING);
                    if (resource.status == Resource.Status.SUCCESS) {
                        Toast.makeText(getContext(), "Deleted", Toast.LENGTH_SHORT).show();
                        navigateBack();
                    } else if (resource.status == Resource.Status.ERROR) {
                        Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show();
                    }
                }));
    }

    private void navigateBack() {
        NavHostFragment.findNavController(this).popBackStack();
    }
}
