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

import android.net.Uri;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.example.petstoremobile.R;
import com.example.petstoremobile.api.PetApi;
import com.example.petstoremobile.api.auth.TokenManager;
import com.example.petstoremobile.databinding.FragmentPetDetailBinding;
import com.example.petstoremobile.dtos.DropdownDTO;
import com.example.petstoremobile.dtos.PetDTO;
import com.example.petstoremobile.utils.ActivityLogger;
import com.example.petstoremobile.utils.DateTimeUtils;
import com.example.petstoremobile.utils.DialogUtils;
import com.example.petstoremobile.utils.FileUtils;
import com.example.petstoremobile.utils.GlideUtils;
import com.example.petstoremobile.utils.ImagePickerHelper;
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.viewmodels.PetDetailViewModel;

import java.io.File;
import java.util.List;
import java.util.Locale;

import javax.inject.Inject;
import javax.inject.Named;

import dagger.hilt.android.AndroidEntryPoint;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;

/**
 * Fragment for displaying and editing pet details.
 */
@AndroidEntryPoint
public class PetDetailFragment extends Fragment {

    private FragmentPetDetailBinding binding;
    private PetDetailViewModel viewModel;
    private ImagePickerHelper imagePickerHelper;
    private boolean isUpdatingUI = false;

    private boolean hasImage = false;
    private boolean isImageChanged = false;
    private boolean isImageRemoved = false;
    private Uri photoUri;

    @Inject @Named("baseUrl") String baseUrl;
    @Inject TokenManager tokenManager;

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

        imagePickerHelper = new ImagePickerHelper(this, "pet_photo.jpg", new ImagePickerHelper.ImagePickerListener() {
            @Override
            public void onImagePicked(Uri uri) {
                photoUri = uri;
                Glide.with(PetDetailFragment.this)
                        .load(uri)
                        .diskCacheStrategy(DiskCacheStrategy.NONE)
                        .skipMemoryCache(true)
                        .into(binding.ivPetImage);
                hasImage = true;
                isImageChanged = true;
                isImageRemoved = false;
            }

            @Override
            public void onImageRemoved() {
                photoUri = null;
                hasImage = false;
                isImageChanged = false;
                isImageRemoved = true;
                binding.ivPetImage.setImageResource(R.drawable.placeholder2);
            }
        });
    }

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

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        setupSpinner();
        observeViewModel();
        handleArguments();
        viewModel.loadInitialFormData();

        binding.btnBack.setOnClickListener(v -> navigateBack());
        binding.btnSavePet.setOnClickListener(v -> savePet());
        binding.btnDeletePet.setOnClickListener(v -> deletePet());
        binding.ivPetImage.setOnClickListener(v -> imagePickerHelper.showImagePickerDialog("Select Pet Image", hasImage));
    }

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

        viewModel.getCustomerList().observe(getViewLifecycleOwner(), list -> {
            PetDetailViewModel.ViewState state = viewModel.getViewState().getValue();
            Long selectedCustomerId = state != null ? state.selectedCustomerId : null;
            updateCustomerSpinnerSelection(selectedCustomerId);
        });

        viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> {
            PetDetailViewModel.ViewState state = viewModel.getViewState().getValue();
            boolean staffCreating = isStaff() && (state == null || !state.isEditing);
            boolean storeEnabled = state == null || state.isStoreEnabled;
            Long selectedStoreId = (staffCreating && storeEnabled) ? tokenManager.getPrimaryStoreId() : (state != null ? state.selectedStoreId : null);
            updateStoreSpinnerSelection(selectedStoreId);
            if (staffCreating && storeEnabled) UIUtils.setViewsEnabled(false, binding.spinnerStore);
        });

        viewModel.getSpeciesList().observe(getViewLifecycleOwner(), list -> {
            PetDetailViewModel.ViewState state = viewModel.getViewState().getValue();
            String selectedSpecies = state != null ? state.selectedSpecies : null;
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerPetSpecies, list,
                    DropdownDTO::getLabel, "-- Select Species --", null, DropdownDTO::getId);
            SpinnerUtils.setSelectionByValue(binding.spinnerPetSpecies, selectedSpecies);
        });

        viewModel.getBreedList().observe(getViewLifecycleOwner(), list -> {
            PetDetailViewModel.ViewState state = viewModel.getViewState().getValue();
            String selectedBreed = state != null ? state.selectedBreed : null;
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerPetBreed, list,
                    DropdownDTO::getLabel, "-- Select Breed --", null, DropdownDTO::getId);
            SpinnerUtils.setSelectionByValue(binding.spinnerPetBreed, selectedBreed);
        });
    }

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

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

    private void savePet() {
        if (!InputValidator.isNotEmpty(binding.etPetName, "Pet Name")) return;
        if (!InputValidator.isSpinnerSelected(binding.spinnerPetSpecies, "Species")) return;
        if (!InputValidator.isSpinnerSelected(binding.spinnerPetBreed, "Breed")) return;
        if (!InputValidator.isPositiveInteger(binding.etPetAge, "Age")) return;
        if (!InputValidator.isPositiveDecimal(binding.etPetPrice, "Price")) return;

        String name = binding.etPetName.getText().toString().trim();
        List<DropdownDTO> speciesOptions = viewModel.getSpeciesList().getValue();
        String species = (speciesOptions != null && binding.spinnerPetSpecies.getSelectedItemPosition() > 0)
                ? speciesOptions.get(binding.spinnerPetSpecies.getSelectedItemPosition() - 1).getLabel()
                : "";

        List<DropdownDTO> breedOptions = viewModel.getBreedList().getValue();
        String breed = (breedOptions != null && binding.spinnerPetBreed.getSelectedItemPosition() > 0)
                ? breedOptions.get(binding.spinnerPetBreed.getSelectedItemPosition() - 1).getLabel()
                : "";
        int age = Integer.parseInt(binding.etPetAge.getText().toString().trim());
        double price = Double.parseDouble(binding.etPetPrice.getText().toString().trim());
        String status = binding.spinnerPetStatus.getSelectedItem().toString();

        Long customerId = null;
        if (binding.spinnerCustomer.getSelectedItemPosition() > 0 && viewModel.getCustomerList().getValue() != null) {
            customerId = viewModel.getCustomerList().getValue().get(binding.spinnerCustomer.getSelectedItemPosition() - 1).getId();
        }

        Long storeId = null;
        if (binding.spinnerStore.getSelectedItemPosition() > 0 && viewModel.getStoreList().getValue() != null) {
            storeId = viewModel.getStoreList().getValue().get(binding.spinnerStore.getSelectedItemPosition() - 1).getId();
        }

        if ("Available".equalsIgnoreCase(status)) {
            if (!InputValidator.isSpinnerSelected(binding.spinnerStore, "Store")) return;
        }
        if ("Owned".equalsIgnoreCase(status)) {
            if (!InputValidator.isSpinnerSelected(binding.spinnerCustomer, "Owner")) return;
        }
        if ("Adopted".equalsIgnoreCase(status)) {
            if (!InputValidator.isSpinnerSelected(binding.spinnerCustomer, "Owner")) return;
            if (!InputValidator.isSpinnerSelected(binding.spinnerStore, "Store")) return;
        }
        if ("Pending".equalsIgnoreCase(status)) {
            if (!InputValidator.isSpinnerSelected(binding.spinnerCustomer, "Owner")) return;
            if (!InputValidator.isSpinnerSelected(binding.spinnerStore, "Store")) return;
        }

        PetDTO petDTO = new PetDTO();
        petDTO.setPetName(name);
        petDTO.setPetSpecies(species);
        petDTO.setPetBreed(breed);
        petDTO.setPetAge(age);
        petDTO.setPetPrice(price);
        petDTO.setPetStatus(status);
        petDTO.setCustomerId(customerId);
        petDTO.setStoreId(storeId);

        boolean ownerChanged = !java.util.Objects.equals(viewModel.getOriginalCustomerId(), customerId);
        if (!isStaff() && viewModel.isEditing() && viewModel.isOriginallyOwnedOrAdopted() && ownerChanged) {
            new AlertDialog.Builder(requireContext())
                    .setTitle("Change Owner")
                    .setMessage("Are you sure you want to change the owner of this pet?")
                    .setPositiveButton("Yes", (d, w) -> performSave(petDTO, name))
                    .setNegativeButton("Cancel", null)
                    .show();
        } else {
            performSave(petDTO, name);
        }
    }

    private void performSave(PetDTO petDTO, String name) {
        viewModel.savePet(petDTO).observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.SUCCESS) {
                if (resource.data != null) {
                    viewModel.setPetId(resource.data.getPetId());
                }
                String msg;
                if (viewModel.isEditing()) {
                    ActivityLogger.logChange(requireContext(), "Pet", "UPDATED", (int) viewModel.getPetId());
                    msg = "Pet updated successfully!";
                } else {
                    ActivityLogger.log(requireContext(), "Added new Pet: " + name);
                    msg = "Pet added successfully!";
                }
                performPendingImageActions(msg);
            } else if (resource.status == Resource.Status.ERROR) {
                Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void deletePet() {
        DialogUtils.showDeleteConfirmDialog(requireContext(), "Pet", () -> {
                viewModel.deletePet().observe(getViewLifecycleOwner(), resource -> {
                    if (resource == null) return;
                    setLoading(resource.status == Resource.Status.LOADING);
                    if (resource.status == Resource.Status.SUCCESS) {
                        ActivityLogger.logChange(requireContext(), "Pet", "DELETED", (int) viewModel.getPetId());
                        Toast.makeText(getContext(), "Pet deleted successfully!", Toast.LENGTH_SHORT).show();
                        navigateToPetList();
                    } else if (resource.status == Resource.Status.ERROR) {
                        Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show();
                    }
                });
        });
    }

    private void navigateToPetList() {
        NavHostFragment.findNavController(this).popBackStack(R.id.nav_pet, false);
    }

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

    private void handleArguments() {
        if (getArguments() != null && getArguments().containsKey("petId")) {
            viewModel.setPetId(getArguments().getLong("petId"));
            loadPetData();
            loadPetImage();
            return;
        }

        viewModel.setPetId(-1);
        hasImage = false;
    }

    private void loadPetImage() {
        String imageUrl = baseUrl + String.format(Locale.US, PetApi.PET_IMAGE_PATH, viewModel.getPetId());
        String token = tokenManager.getToken();
        GlideUtils.loadImageWithToken(requireContext(), binding.ivPetImage, imageUrl, token, R.drawable.placeholder2, new GlideUtils.ImageLoadListener() {
            @Override
            public void onResourceReady() {
                hasImage = true;
            }

            @Override
            public void onLoadFailed() {
                hasImage = false;
            }
        });
    }

    private void performPendingImageActions(String successMsg) {
        if (isImageRemoved) {
            viewModel.deletePetImage().observe(getViewLifecycleOwner(), resource -> {
                if (resource == null) return;
                setLoading(resource.status == Resource.Status.LOADING);
                if (resource.status != Resource.Status.LOADING) {
                    if (resource.status == Resource.Status.SUCCESS) {
                        Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(getContext(), successMsg + " (but image removal failed)", Toast.LENGTH_SHORT).show();
                    }
                    navigateToPetList();
                }
            });
        } else if (isImageChanged && photoUri != null) {
            uploadPetImageAndNavigate(photoUri, successMsg);
        } else {
            Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
            navigateToPetList();
        }
    }

    private void uploadPetImageAndNavigate(Uri uri, String successMsg) {
        File file = FileUtils.getFileFromUri(requireContext(), uri);
        if (file == null) {
            Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
            navigateToPetList();
            return;
        }

        RequestBody requestFile = RequestBody.create(file, MediaType.parse(requireContext().getContentResolver().getType(uri)));
        MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile);

        viewModel.uploadPetImage(body).observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status != Resource.Status.LOADING) {
                if (resource.status == Resource.Status.SUCCESS) {
                    Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(getContext(), successMsg + " (but image upload failed)", Toast.LENGTH_SHORT).show();
                }
                navigateToPetList();
            }
        });
    }

    private void loadPetData() {
        viewModel.loadPet().observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
                PetDTO p = resource.data;
                binding.etPetName.setText(p.getPetName());
                binding.etPetAge.setText(String.valueOf(p.getPetAge()));
                if (p.getPetPrice() != null) {
                    binding.etPetPrice.setText(String.format(Locale.getDefault(), "%.2f", p.getPetPrice()));
                }
            } else if (resource.status == Resource.Status.ERROR) {
                Toast.makeText(getContext(), "Failed to load pet: " + resource.message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void updateCustomerSpinnerSelection(Long selectedCustomerId) {
        SpinnerUtils.populateSpinner(
                requireContext(),
                binding.spinnerCustomer,
                viewModel.getCustomerList().getValue(),
                DropdownDTO::getLabel,
                "No Owner",
                selectedCustomerId,
                DropdownDTO::getId
        );
    }

    private void updateStoreSpinnerSelection(Long selectedStoreId) {
        SpinnerUtils.populateSpinner(
                requireContext(),
                binding.spinnerStore,
                viewModel.getStoreList().getValue(),
                DropdownDTO::getLabel,
                "None",
                selectedStoreId,
                DropdownDTO::getId
        );
    }

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

        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerPetSpecies, p -> {
            if (isUpdatingUI) return;
            viewModel.onSpeciesSelected(p);
        });

        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerPetBreed, p -> {
            if (isUpdatingUI) return;
            viewModel.onBreedSelected(p);
        });

        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerCustomer, p -> {
            if (isUpdatingUI) return;
            viewModel.onCustomerSelected(p);
        });
        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerStore, p -> {
            if (isUpdatingUI) return;
            viewModel.onStoreSelected(p);
        });
        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerPetStatus, p -> {
            if (isUpdatingUI) return;
            String status = binding.spinnerPetStatus.getItemAtPosition(p).toString();
            clearSpinnerError(binding.spinnerCustomer);
            clearSpinnerError(binding.spinnerStore);
            viewModel.onStatusSelected(status);
        });
    }

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

        binding.tvMode.setText(state.modeTitle);
        binding.tvPetId.setText(DateTimeUtils.formatId(viewModel.getPetId()));
        binding.tvPetId.setVisibility(state.isPetIdVisible ? View.VISIBLE : View.GONE);
        binding.btnDeletePet.setVisibility(state.isDeleteVisible ? View.VISIBLE : View.GONE);
        binding.btnSavePet.setText(state.saveButtonText);

        UIUtils.setViewsEnabled(state.isSpeciesEnabled, binding.spinnerPetSpecies);
        UIUtils.setViewsEnabled(state.isBreedEnabled, binding.spinnerPetBreed);
        UIUtils.setViewsEnabled(state.isCustomerEnabled, binding.spinnerCustomer);
        UIUtils.setViewsEnabled(state.isStoreEnabled, binding.spinnerStore);

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

        updateCustomerSpinnerSelection(state.selectedCustomerId);
        updateStoreSpinnerSelection(state.selectedStoreId);

        List<DropdownDTO> species = viewModel.getSpeciesList().getValue();
        if (species != null) {
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerPetSpecies, species,
                    DropdownDTO::getLabel, "-- Select Species --", null, DropdownDTO::getId);
            SpinnerUtils.setSelectionByValue(binding.spinnerPetSpecies, state.selectedSpecies);
        }

        List<DropdownDTO> breeds = viewModel.getBreedList().getValue();
        if (breeds != null) {
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerPetBreed, breeds,
                    DropdownDTO::getLabel, "-- Select Breed --", null, DropdownDTO::getId);
            SpinnerUtils.setSelectionByValue(binding.spinnerPetBreed, state.selectedBreed);
        }

        if (!state.isCustomerEnabled && binding.spinnerCustomer.getSelectedItemPosition() != 0) {
            binding.spinnerCustomer.setSelection(0);
        }
        if (!state.isStoreEnabled && binding.spinnerStore.getSelectedItemPosition() != 0) {
            binding.spinnerStore.setSelection(0);
        }

        if (isStaff() && !state.isEditing && state.isStoreEnabled) {
            updateStoreSpinnerSelection(tokenManager.getPrimaryStoreId());
            UIUtils.setViewsEnabled(false, binding.spinnerStore);
        }

        if (isStaff() && state.isEditing && viewModel.isOriginallyOwnedOrAdopted()) {
            UIUtils.setViewsEnabled(false, binding.spinnerCustomer, binding.spinnerPetStatus, binding.spinnerStore);
        }

        isUpdatingUI = false;
    }

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

    private void clearSpinnerError(Spinner spinner) {
        View selectedView = spinner.getSelectedView();
        if (selectedView instanceof TextView) {
            ((TextView) selectedView).setError(null);
        }
    }
}
