package com.example.petstoremobile.viewmodels;

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

import com.example.petstoremobile.dtos.CouponDTO;
import com.example.petstoremobile.dtos.CustomerDTO;
import com.example.petstoremobile.dtos.DropdownDTO;
import com.example.petstoremobile.dtos.ProductDTO;
import com.example.petstoremobile.dtos.SaleDTO;
import com.example.petstoremobile.repositories.CouponRepository;
import com.example.petstoremobile.repositories.CustomerRepository;
import com.example.petstoremobile.repositories.ProductRepository;
import com.example.petstoremobile.repositories.SaleRepository;
import com.example.petstoremobile.repositories.StoreRepository;
import com.example.petstoremobile.utils.Resource;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

import dagger.hilt.android.lifecycle.HiltViewModel;

@HiltViewModel
public class SaleDetailViewModel extends ViewModel {
    private final SaleRepository saleRepository;
    private final StoreRepository storeRepository;
    private final CustomerRepository customerRepository;
    private final ProductRepository productRepository;
    private final CouponRepository couponRepository;

    private long saleId = -1;
    private boolean viewOnly = false;

    private final MutableLiveData<List<DropdownDTO>> storeList = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<DropdownDTO>> customerList = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<ProductDTO>> productList = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<SaleDTO.SaleItemDTO>> cartItems = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<CouponDTO> appliedCoupon = new MutableLiveData<>(null);
    private final MutableLiveData<CustomerDTO> selectedCustomerData = new MutableLiveData<>(null);
    private final MutableLiveData<Boolean> useLoyaltyPoints = new MutableLiveData<>(false);
    private final MutableLiveData<Boolean> isLoading = new MutableLiveData<>(false);

    @Inject
    public SaleDetailViewModel(SaleRepository saleRepository, StoreRepository storeRepository,
                               CustomerRepository customerRepository, ProductRepository productRepository,
                               CouponRepository couponRepository) {
        this.saleRepository = saleRepository;
        this.storeRepository = storeRepository;
        this.customerRepository = customerRepository;
        this.productRepository = productRepository;
        this.couponRepository = couponRepository;
    }

    public void setSaleId(long id, boolean viewOnly) {
        this.saleId = id;
        this.viewOnly = viewOnly;
    }

    public long getSaleId() { return saleId; }
    public boolean isViewOnly() { return viewOnly; }

    public LiveData<Resource<SaleDTO>> loadSaleDetails() {
        return saleRepository.getSaleById(saleId);
    }

    public LiveData<Resource<List<DropdownDTO>>> loadStores() {
        return storeRepository.getStoreDropdowns();
    }

    public LiveData<Resource<List<DropdownDTO>>> loadCustomers() {
        return customerRepository.getCustomerDropdowns();
    }

    public LiveData<Resource<com.example.petstoremobile.dtos.PageResponse<ProductDTO>>> loadProducts() {
        return productRepository.getAllProducts(null, null, 0, 200, null);
    }

    public LiveData<Resource<SaleDTO>> createSale(SaleDTO sale) {
        return saleRepository.createSale(sale);
    }

    public void setStoreList(List<DropdownDTO> list) { storeList.setValue(list); }
    public LiveData<List<DropdownDTO>> getStoreList() { return storeList; }

    public void setCustomerList(List<DropdownDTO> list) { customerList.setValue(list); }
    public LiveData<List<DropdownDTO>> getCustomerList() { return customerList; }

    public void setProductList(List<ProductDTO> list) { productList.setValue(list); }
    public LiveData<List<ProductDTO>> getProductList() { return productList; }

    public void addToCart(SaleDTO.SaleItemDTO item) {
        List<SaleDTO.SaleItemDTO> currentCart = new ArrayList<>(cartItems.getValue());
        currentCart.add(item);
        cartItems.setValue(currentCart);
    }

    public void removeFromCart(Long prodId) {
        List<SaleDTO.SaleItemDTO> currentCart = new ArrayList<>(cartItems.getValue());
        currentCart.removeIf(item -> item.getProdId().equals(prodId));
        cartItems.setValue(currentCart);
    }

    public LiveData<List<SaleDTO.SaleItemDTO>> getCartItems() { return cartItems; }

    public LiveData<Resource<CouponDTO>> lookupCoupon(String code) {
        return couponRepository.getCouponByCode(code);
    }

    public void setAppliedCoupon(CouponDTO coupon) {
        appliedCoupon.setValue(coupon);
    }

    public void setUseLoyaltyPoints(boolean use) {
        useLoyaltyPoints.setValue(use);
    }

    public LiveData<Boolean> getUseLoyaltyPoints() {
        return useLoyaltyPoints;
    }

    public LiveData<CustomerDTO> getSelectedCustomerData() {
        return selectedCustomerData;
    }

    public void selectCustomer(Long customerId) {
        if (customerId == null) {
            selectedCustomerData.setValue(null);
            useLoyaltyPoints.setValue(false);
            return;
        }
        customerRepository.getCustomerById(customerId).observeForever(new androidx.lifecycle.Observer<Resource<CustomerDTO>>() {
            @Override
            public void onChanged(Resource<CustomerDTO> resource) {
                if (resource != null && resource.status == Resource.Status.SUCCESS) {
                    selectedCustomerData.setValue(resource.data);
                }
            }
        });
    }

    public void clearCoupon() {
        appliedCoupon.setValue(null);
    }

    public LiveData<CouponDTO> getAppliedCoupon() {
        return appliedCoupon;
    }

    public Long getAppliedCouponId() {
        CouponDTO coupon = appliedCoupon.getValue();
        return coupon != null ? coupon.getCouponId() : null;
    }

    public BigDecimal calculateDiscount() {
        return calculateCouponDiscount().add(calculateLoyaltyDiscount());
    }

    public BigDecimal calculateCouponDiscount() {
        CouponDTO coupon = appliedCoupon.getValue();
        if (coupon == null || coupon.getDiscountValue() == null) return BigDecimal.ZERO;
        BigDecimal subtotal = calculateSubtotal();
        if ("PERCENTAGE".equalsIgnoreCase(coupon.getDiscountType())) {
            return subtotal.multiply(coupon.getDiscountValue()).divide(BigDecimal.valueOf(100), 2, java.math.RoundingMode.HALF_UP);
        } else {
            return coupon.getDiscountValue().min(subtotal);
        }
    }

    public BigDecimal calculateLoyaltyDiscount() {
        if (Boolean.FALSE.equals(useLoyaltyPoints.getValue())) return BigDecimal.ZERO;
        CustomerDTO customer = selectedCustomerData.getValue();
        if (customer == null || customer.getLoyaltyPoints() == null || customer.getLoyaltyPoints() < 20) {
            return BigDecimal.ZERO;
        }

        BigDecimal subtotalAfterCoupon = calculateSubtotal().subtract(calculateCouponDiscount());
        int maxPointsNeeded = subtotalAfterCoupon.multiply(BigDecimal.valueOf(20)).intValue();
        int pointsToUse = Math.min(customer.getLoyaltyPoints(), maxPointsNeeded);

        return BigDecimal.valueOf(pointsToUse).multiply(BigDecimal.valueOf(0.05)).setScale(2, java.math.RoundingMode.HALF_UP);
    }

    public int calculatePointsToUse() {
        BigDecimal loyaltyDiscount = calculateLoyaltyDiscount();
        return loyaltyDiscount.divide(BigDecimal.valueOf(0.05), 0, java.math.RoundingMode.HALF_UP).intValue();
    }

    public BigDecimal calculateSubtotal() {
        BigDecimal total = BigDecimal.ZERO;
        List<SaleDTO.SaleItemDTO> items = cartItems.getValue();
        List<ProductDTO> products = productList.getValue();
        if (items != null && products != null) {
            for (SaleDTO.SaleItemDTO item : items) {
                for (ProductDTO p : products) {
                    if (p.getProdId().equals(item.getProdId()) && p.getProdPrice() != null) {
                        total = total.add(p.getProdPrice().multiply(BigDecimal.valueOf(item.getQuantity())));
                        break;
                    }
                }
            }
        }
        return total;
    }

    public LiveData<Boolean> getIsLoading() {
        return isLoading;
    }

    public void setLoading(boolean loading) {
        isLoading.setValue(loading);
    }
}
