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

import android.net.Uri;
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.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.example.petstoremobile.R;
import com.example.petstoremobile.api.*;
import com.example.petstoremobile.api.auth.TokenManager;
import com.example.petstoremobile.databinding.FragmentProductDetailBinding;
import com.example.petstoremobile.dtos.*;
import com.example.petstoremobile.viewmodels.ProductDetailViewModel;
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 java.io.File;
import java.math.BigDecimal;
import java.util.*;

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 product details, including image selection.
 */
@AndroidEntryPoint
public class ProductDetailFragment extends Fragment {

    private FragmentProductDetailBinding binding;
    private ProductDetailViewModel viewModel;
    private ImagePickerHelper imagePickerHelper;

    private long preselectedCategoryId = -1;
    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(ProductDetailViewModel.class);

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

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

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

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

        observeViewModel();
        handleArguments();

        binding.btnProductBack.setOnClickListener(v -> navigateBack());
        binding.btnSaveProduct.setOnClickListener(v -> saveProduct());
        binding.btnDeleteProduct.setOnClickListener(v -> confirmDelete());
        binding.ivProductImage.setOnClickListener(v -> imagePickerHelper.showImagePickerDialog("Select Product Image", hasImage));
    }

    private void observeViewModel() {
        viewModel.getCategoryList().observe(getViewLifecycleOwner(), list -> updateCategorySpinner());

        viewModel.loadCategories().observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
                viewModel.setCategoryList(resource.data);
            }
        });
    }

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

    private void updateCategorySpinner() {
        SpinnerUtils.populateSpinner(requireContext(), binding.spinnerProductCategory, viewModel.getCategoryList().getValue(),
                DropdownDTO::getLabel, "-- Select Category --",
                preselectedCategoryId, DropdownDTO::getId);
    }

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

    private void handleArguments() {
        Bundle a = getArguments();
        if (a != null && a.containsKey("prodId")) {
            long prodId = a.getLong("prodId");
            viewModel.setProdId(prodId);
            binding.tvProductMode.setText("Edit Product");
            binding.tvProductId.setText(DateTimeUtils.formatId(prodId));
            binding.tvProductId.setVisibility(View.VISIBLE);
            binding.btnDeleteProduct.setVisibility(View.VISIBLE);
            loadProductData();
            loadProductImage();
        } else {
            viewModel.setProdId(-1);
            binding.tvProductMode.setText("Add Product");
            binding.btnDeleteProduct.setVisibility(View.GONE);
            binding.tvProductId.setVisibility(View.GONE);
            hasImage = false;
        }
    }

    private void loadProductData() {
        viewModel.loadProduct().observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
                ProductDTO p = resource.data;
                binding.etProductName.setText(p.getProdName());
                binding.etProductDesc.setText(p.getProdDesc());
                binding.etProductPrice.setText(p.getProdPrice() != null ? p.getProdPrice().toString() : "");
                preselectedCategoryId = p.getCategoryId() != null ? p.getCategoryId() : -1;
                updateCategorySpinner();
            } else if (resource.status == Resource.Status.ERROR) {
                Toast.makeText(getContext(), "Failed to load product: " + resource.message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void loadProductImage() {
        String imageUrl = baseUrl + String.format(Locale.US, ProductApi.PRODUCT_IMAGE_PATH, viewModel.getProdId());
        String token = tokenManager.getToken();

        GlideUtils.loadImageWithToken(requireContext(), binding.ivProductImage, 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.deleteProductImage().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();
                    }
                    navigateBack();
                }
            });
        } else if (isImageChanged && photoUri != null) {
            uploadProductImageAndNavigate(photoUri, successMsg);
        } else {
            Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
            navigateBack();
        }
    }

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

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

        viewModel.uploadProductImage(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();
                }
                navigateBack();
            }
        });
    }

    private void saveProduct() {
        if (!InputValidator.isNotEmpty(binding.etProductName, "Product Name")) return;
        if (!InputValidator.isSpinnerSelected(binding.spinnerProductCategory, "Category")) return;
        if (!InputValidator.isPositiveDecimal(binding.etProductPrice, "Price")) return;

        String name = binding.etProductName.getText().toString().trim();
        String desc = binding.etProductDesc.getText().toString().trim();
        BigDecimal price = new BigDecimal(binding.etProductPrice.getText().toString().trim());

        DropdownDTO category = viewModel.getCategoryList().getValue().get(binding.spinnerProductCategory.getSelectedItemPosition() - 1);
        ProductDTO dto = new ProductDTO(name, category.getId(), desc, price);

        viewModel.saveProduct(dto).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) {
                    if (resource.data != null) {
                        viewModel.setProdId(resource.data.getProdId());
                    }
                    performPendingImageActions(viewModel.isEditing() ? "Updated" : "Saved");
                } else {
                    Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    private void confirmDelete() {
        DialogUtils.showDeleteConfirmDialog(requireContext(), "Product", () ->
                viewModel.deleteProduct().observe(getViewLifecycleOwner(), resource -> {
                    if (resource == null) return;
                    setLoading(resource.status == Resource.Status.LOADING);
                    if (resource.status == Resource.Status.SUCCESS) {
                        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();
    }
}
