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

import android.os.Bundle;
import android.util.Log;
import android.view.*;
import android.widget.*;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment;
import com.example.petstoremobile.R;
import com.example.petstoremobile.databinding.FragmentSaleDetailBinding;
import com.example.petstoremobile.dtos.*;
import com.example.petstoremobile.viewmodels.SaleDetailViewModel;
import com.example.petstoremobile.utils.SpinnerUtils;
import com.example.petstoremobile.utils.DialogUtils;
import com.example.petstoremobile.utils.DateTimeUtils;
import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.UIUtils;
import com.example.petstoremobile.api.auth.TokenManager;

import javax.inject.Inject;

import dagger.hilt.android.AndroidEntryPoint;
import java.math.BigDecimal;
import java.util.*;

@AndroidEntryPoint
public class SaleDetailFragment extends Fragment {

    private FragmentSaleDetailBinding binding;
    private SaleDetailViewModel viewModel;

    @Inject TokenManager tokenManager;

    private final String[] PAYMENT_METHODS = { "Cash", "Card"};

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        binding = FragmentSaleDetailBinding.inflate(inflater, container, false);
        viewModel = new ViewModelProvider(this).get(SaleDetailViewModel.class);

        SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerPaymentMethod, PAYMENT_METHODS);

        observeViewModel();
        handleArguments();

        if (viewModel.isViewOnly()) {
            binding.llAddItemRow.setVisibility(View.GONE);
            binding.llCouponInput.setVisibility(View.GONE);
            binding.btnSaveSale.setVisibility(View.GONE);
            UIUtils.setViewsEnabled(false, binding.spinnerSaleStore, binding.spinnerSaleCustomer, binding.spinnerPaymentMethod);
        } else {
            loadData();
            setupAddItem();
            setupCoupon();
        }

        binding.btnSaleBack.setOnClickListener(v -> navigateBack());
        binding.btnSaveSale.setOnClickListener(v -> saveSale());
        binding.btnRefundSale.setOnClickListener(v -> showRefundDialog());

        return binding.getRoot();
    }

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

    private boolean isAdmin() {
        return "ADMIN".equalsIgnoreCase(tokenManager.getRole());
    }

    private void observeViewModel() {
        viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> {
            Long primaryStoreId = tokenManager.getPrimaryStoreId();
            Long selectedStoreId = isStaff() ? primaryStoreId : -1L;
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerSaleStore, list,
                    DropdownDTO::getLabel, "-- Select Store --", selectedStoreId, DropdownDTO::getId);
            if (isStaff()) {
                UIUtils.setViewsEnabled(false, binding.spinnerSaleStore);
                if (primaryStoreId == null) {
                    UIUtils.showToast(requireContext(), "No store assigned to your account. Contact an admin.");
                }
            }
        });

        viewModel.getCustomerList().observe(getViewLifecycleOwner(), list -> {
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerSaleCustomer, list,
                    DropdownDTO::getLabel, "-- No Customer --", -1L, DropdownDTO::getId);
        });

        viewModel.getProductList().observe(getViewLifecycleOwner(), list -> {
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerSaleProduct, list,
                    ProductDTO::getProdName, "Select Product", -1L, ProductDTO::getProdId);
        });

        viewModel.getCartItems().observe(getViewLifecycleOwner(), items -> {
            renderCartItems();
            updateTotal();
        });

        viewModel.getSelectedCustomerData().observe(getViewLifecycleOwner(), customer -> {
            if (customer != null && !viewModel.isViewOnly()) {
                binding.llLoyaltyPoints.setVisibility(View.VISIBLE);
                binding.tvAvailablePoints.setText("(Available: " + customer.getLoyaltyPoints() + ")");
                binding.cbUseLoyaltyPoints.setEnabled(customer.getLoyaltyPoints() >= 20);
            } else {
                binding.llLoyaltyPoints.setVisibility(View.GONE);
                binding.cbUseLoyaltyPoints.setChecked(false);
            }
            updateTotal();
        });
    }

    private void handleArguments() {
        Bundle a = getArguments();
        if (a != null && a.containsKey("saleId")) {
            long saleId = a.getLong("saleId");
            boolean viewOnly = a.getBoolean("viewOnly", false);
            viewModel.setSaleId(saleId, viewOnly);
            
            binding.tvSaleMode.setText("Sale #" + DateTimeUtils.formatId(saleId));
            binding.tvSaleDetailId.setText("ID: " + DateTimeUtils.formatId(saleId));

            boolean isRefund = a.getBoolean("isRefund", false);
            if (isRefund || isAdmin()) {
                binding.btnRefundSale.setVisibility(View.GONE);
            }

            if (viewOnly) {
                binding.btnSaveSale.setVisibility(View.GONE);
                UIUtils.setViewsEnabled(false, 
                        binding.spinnerSaleStore, 
                        binding.spinnerSaleCustomer, 
                        binding.spinnerPaymentMethod);
                binding.llAddItemRow.setVisibility(View.GONE);
                binding.llExtraInfo.setVisibility(View.VISIBLE);
                binding.llCustomerInfo.setVisibility(View.VISIBLE);
                binding.tvCustomerLabel.setVisibility(View.GONE);
                binding.spinnerSaleCustomer.setVisibility(View.GONE);
                binding.spinnerSaleStore.setVisibility(View.GONE);
                binding.spinnerPaymentMethod.setVisibility(View.GONE);
                binding.tvSaleStore.setVisibility(View.VISIBLE);
                binding.tvSalePaymentMethod.setVisibility(View.VISIBLE);

                binding.btnRefundSale.setVisibility((isRefund || isAdmin()) ? View.GONE : View.VISIBLE);
            }

            loadSaleDetails();
        } else {
            viewModel.setSaleId(-1, false);
            binding.tvSaleMode.setText("New Sale");
            binding.tvSaleDetailId.setVisibility(View.GONE);
            binding.btnRefundSale.setVisibility(View.GONE);
            binding.llExtraInfo.setVisibility(View.GONE);
        }
    }

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

    private void loadData() {
        viewModel.loadStores().observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.SUCCESS && resource.data != null) viewModel.setStoreList(resource.data);
        });
        viewModel.loadCustomers().observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.SUCCESS && resource.data != null) viewModel.setCustomerList(resource.data);
        });
        viewModel.loadProducts().observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.SUCCESS && resource.data != null) viewModel.setProductList(resource.data.getContent());
        });
    }

    private void loadSaleDetails() {
        viewModel.loadSaleDetails().observe(getViewLifecycleOwner(), resource -> {
            if (resource == null) return;
            setLoading(resource.status == Resource.Status.LOADING);
            if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
                SaleDTO sale = resource.data;
                binding.tvSaleDetailTotal.setText("Total: $" + String.format(Locale.getDefault(), "%.2f", sale.getTotalAmount()));
                binding.tvSaleSubtotal.setText("$" + String.format(Locale.getDefault(), "%.2f", (sale.getSubtotalAmount() != null ? sale.getSubtotalAmount() : sale.getTotalAmount())));
                
                if (sale.getCouponDiscountAmount() != null && sale.getCouponDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
                    binding.llCouponDiscount.setVisibility(View.VISIBLE);
                    binding.tvSaleCouponDiscount.setText("-$" + String.format(Locale.getDefault(), "%.2f", sale.getCouponDiscountAmount()));
                } else {
                    binding.llCouponDiscount.setVisibility(View.GONE);
                }

                if (sale.getEmployeeDiscountAmount() != null && sale.getEmployeeDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
                    binding.llEmployeeDiscount.setVisibility(View.VISIBLE);
                    binding.tvSaleEmployeeDiscount.setText("-$" + String.format(Locale.getDefault(), "%.2f", sale.getEmployeeDiscountAmount()));
                } else {
                    binding.llEmployeeDiscount.setVisibility(View.GONE);
                }

                if (sale.getLoyaltyDiscountAmount() != null && sale.getLoyaltyDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
                    binding.llLoyaltyDiscount.setVisibility(View.VISIBLE);
                    binding.tvSaleLoyaltyDiscount.setText("-$" + String.format(Locale.getDefault(), "%.2f", sale.getLoyaltyDiscountAmount()));
                    if (sale.getPointsUsed() != null && sale.getPointsUsed() > 0) {
                        binding.tvLoyaltyDiscountLabel.setText("Loyalty Discount (" + sale.getPointsUsed() + " pts):");
                    }
                } else {
                    binding.llLoyaltyDiscount.setVisibility(View.GONE);
                }

                binding.tvSaleChannel.setText(sale.getChannel() != null ? sale.getChannel() : "—");
                binding.tvSalePoints.setText(String.valueOf(sale.getPointsEarned() != null ? sale.getPointsEarned() : 0));
                binding.tvSaleStore.setText(sale.getStoreName() != null ? sale.getStoreName() : "—");
                binding.tvSaleCustomer.setText(sale.getCustomerName() != null ? sale.getCustomerName() : "No Customer");
                binding.tvSalePaymentMethod.setText(sale.getPaymentMethod() != null ? sale.getPaymentMethod() : "—");

                if (sale.getIsRefund() != null && sale.getIsRefund()) {
                    binding.btnRefundSale.setVisibility(View.GONE);
                }

                SpinnerUtils.setSelectionByValue(binding.spinnerPaymentMethod, sale.getPaymentMethod());

                if (sale.getItems() != null) {
                    binding.llSaleItems.removeAllViews();
                    for (SaleDTO.SaleItemDTO item : sale.getItems()) {
                        addItemRow(item.getProductName(), Math.abs(item.getQuantity()), item.getUnitPrice(), null);
                    }
                }
            }
        });
    }

    private void setupCoupon() {
        binding.btnApplyCoupon.setOnClickListener(v -> {
            String code = binding.etCouponCode.getText().toString().trim();
            if (code.isEmpty()) {
                UIUtils.showToast(getContext(), "Enter a coupon code");
                return;
            }
            setLoading(true);
            viewModel.lookupCoupon(code).observe(getViewLifecycleOwner(), resource -> {
                if (resource == null) return;
                setLoading(resource.status == Resource.Status.LOADING);
                if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
                    CouponDTO coupon = resource.data;
                    if (Boolean.FALSE.equals(coupon.getActive())) {
                        showCouponError("This coupon is no longer active.");
                        return;
                    }
                    if (coupon.getMinOrderAmount() != null &&
                            viewModel.calculateSubtotal().compareTo(coupon.getMinOrderAmount()) < 0) {
                        showCouponError("Minimum order of $" + coupon.getMinOrderAmount() + " required.");
                        return;
                    }
                    viewModel.setAppliedCoupon(coupon);
                    applyAppliedCouponUI(coupon);
                    updateTotal();
                } else if (resource.status == Resource.Status.ERROR) {
                    showCouponError("Invalid coupon code.");
                }
            });
        });

        binding.btnClearCoupon.setOnClickListener(v -> {
            viewModel.clearCoupon();
            binding.etCouponCode.setText("");
            binding.tvCouponInfo.setVisibility(View.GONE);
            binding.btnClearCoupon.setVisibility(View.GONE);
            binding.btnApplyCoupon.setVisibility(View.VISIBLE);
            binding.etCouponCode.setEnabled(true);
            binding.llCouponDiscount.setVisibility(View.GONE);
            updateTotal();
        });
    }

    private void applyAppliedCouponUI(CouponDTO coupon) {
        String info;
        if ("PERCENTAGE".equalsIgnoreCase(coupon.getDiscountType())) {
            info = coupon.getDiscountValue().stripTrailingZeros().toPlainString() + "% off applied";
        } else {
            info = "$" + coupon.getDiscountValue() + " off applied";
        }
        binding.tvCouponInfo.setText(info);
        binding.tvCouponInfo.setTextColor(0xFF4CAF50);
        binding.tvCouponInfo.setVisibility(View.VISIBLE);
        binding.btnClearCoupon.setVisibility(View.VISIBLE);
        binding.btnApplyCoupon.setVisibility(View.GONE);
        binding.etCouponCode.setEnabled(false);
    }

    private void showCouponError(String message) {
        binding.tvCouponInfo.setText(message);
        binding.tvCouponInfo.setTextColor(0xFFE53935);
        binding.tvCouponInfo.setVisibility(View.VISIBLE);
    }

    private void setupAddItem() {
        binding.btnAddItem.setOnClickListener(v -> {
            if (!InputValidator.isSpinnerSelected(binding.spinnerSaleProduct, "Product")) return;
            if (!InputValidator.isAtLeastOne(binding.etSaleQuantity, "Quantity")) return;

            int qty = Integer.parseInt(binding.etSaleQuantity.getText().toString().trim());
            ProductDTO product = viewModel.getProductList().getValue().get(binding.spinnerSaleProduct.getSelectedItemPosition() - 1);

            for (SaleDTO.SaleItemDTO existing : viewModel.getCartItems().getValue()) {
                if (existing.getProdId().equals(product.getProdId())) {
                    UIUtils.showToast(getContext(), "Product already added");
                    return;
                }
            }

            viewModel.addToCart(new SaleDTO.SaleItemDTO(product.getProdId(), qty));
            binding.etSaleQuantity.setText("");
        });
        SpinnerUtils.setOnIndexSelectedListener(binding.spinnerSaleCustomer, p -> {
            if (p > 0) {
                Long id = viewModel.getCustomerList().getValue().get(p - 1).getId();
                viewModel.selectCustomer(id);
            } else {
                viewModel.selectCustomer(null);
            }
        });

        binding.cbUseLoyaltyPoints.setOnCheckedChangeListener((v, checked) -> {
            viewModel.setUseLoyaltyPoints(checked);
            updateTotal();
        });
    }

    private void renderCartItems() {
        binding.llSaleItems.removeAllViews();
        List<SaleDTO.SaleItemDTO> items = viewModel.getCartItems().getValue();
        List<ProductDTO> products = viewModel.getProductList().getValue();
        if (items == null || products == null) return;

        for (SaleDTO.SaleItemDTO item : items) {
            String name = "Unknown";
            BigDecimal price = BigDecimal.ZERO;
            for (ProductDTO p : products) {
                if (p.getProdId().equals(item.getProdId())) {
                    name = p.getProdName();
                    price = p.getProdPrice();
                    break;
                }
            }
            addItemRow(name, item.getQuantity(), price, item.getProdId());
        }
    }

    private void addItemRow(String name, int qty, BigDecimal price, Long prodId) {
        if (getContext() == null) return;
        LinearLayout row = new LinearLayout(getContext());
        row.setOrientation(LinearLayout.HORIZONTAL);
        row.setPadding(0, 8, 0, 8);
        row.setGravity(android.view.Gravity.CENTER_VERTICAL);

        TextView tvName = new TextView(getContext());
        tvName.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 2f));
        tvName.setText(name);

        TextView tvQty = new TextView(getContext());
        tvQty.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f));
        tvQty.setText("x" + qty);

        TextView tvPrice = new TextView(getContext());
        tvPrice.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f));
        tvPrice.setText(price != null ? "$" + String.format(Locale.getDefault(), "%.2f", price) : "");

        row.addView(tvName);
        row.addView(tvQty);
        row.addView(tvPrice);

        if (prodId != null) {
            Button btnRemove = new Button(getContext());
            btnRemove.setLayoutParams(new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
            btnRemove.setText("✕");
            btnRemove.setTextSize(12f);
            btnRemove.setBackgroundTintList(android.content.res.ColorStateList.valueOf(0xFFE53935));
            btnRemove.setTextColor(0xFFFFFFFF);
            btnRemove.setPadding(16, 4, 16, 4);
            btnRemove.setOnClickListener(v -> viewModel.removeFromCart(prodId));
            row.addView(btnRemove);
        }

        binding.llSaleItems.addView(row);
    }

    private void updateTotal() {
        BigDecimal subtotal = viewModel.calculateSubtotal();
        BigDecimal couponDiscount = viewModel.calculateCouponDiscount();
        BigDecimal loyaltyDiscount = viewModel.calculateLoyaltyDiscount();
        BigDecimal total = subtotal.subtract(couponDiscount).subtract(loyaltyDiscount);
        
        binding.tvSaleSubtotal.setText("$" + String.format(Locale.getDefault(), "%.2f", subtotal));
        
        if (couponDiscount.compareTo(BigDecimal.ZERO) > 0) {
            binding.llCouponDiscount.setVisibility(View.VISIBLE);
            binding.tvSaleCouponDiscount.setText("-$" + String.format(Locale.getDefault(), "%.2f", couponDiscount));
        } else {
            binding.llCouponDiscount.setVisibility(View.GONE);
        }

        if (loyaltyDiscount.compareTo(BigDecimal.ZERO) > 0) {
            binding.llLoyaltyDiscount.setVisibility(View.VISIBLE);
            binding.tvLoyaltyDiscountLabel.setText("Loyalty Discount (" + viewModel.calculatePointsToUse() + " pts):");
            binding.tvSaleLoyaltyDiscount.setText("-$" + String.format(Locale.getDefault(), "%.2f", loyaltyDiscount));
        } else {
            binding.llLoyaltyDiscount.setVisibility(View.GONE);
        }
        
        binding.tvSaleDetailTotal.setText("Total: $" + String.format(Locale.getDefault(), "%.2f", total));

        CustomerDTO customer = viewModel.getSelectedCustomerData().getValue();
        if (customer != null && !viewModel.isViewOnly()) {
            int pointsToEarn = total.max(BigDecimal.ZERO).intValue();
            binding.tvPointsToEarn.setText("+" + pointsToEarn + " pts");
            binding.llPointsToEarn.setVisibility(View.VISIBLE);
        } else {
            binding.llPointsToEarn.setVisibility(View.GONE);
        }
    }

    private void saveSale() {
        if (!InputValidator.isSpinnerSelected(binding.spinnerSaleStore, "Store")) return;

        if (viewModel.getCartItems().getValue() == null || viewModel.getCartItems().getValue().isEmpty()) {
            UIUtils.showToast(getContext(), "Add at least one item");
            return;
        }

        DropdownDTO store = viewModel.getStoreList().getValue().get(binding.spinnerSaleStore.getSelectedItemPosition() - 1);
        String payment = PAYMENT_METHODS[binding.spinnerPaymentMethod.getSelectedItemPosition()];

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

        SaleDTO dto = new SaleDTO(store.getId(), payment, viewModel.getCartItems().getValue(), false, null, customerId);
        dto.setCouponId(viewModel.getAppliedCouponId());
        
        if (Boolean.TRUE.equals(viewModel.getUseLoyaltyPoints().getValue())) {
            dto.setPointsUsed(viewModel.calculatePointsToUse());
        }

        viewModel.createSale(dto).observe(getViewLifecycleOwner(), resource -> {
            if (resource != null) {
                setLoading(resource.status == Resource.Status.LOADING);
                if (resource.status == Resource.Status.SUCCESS) {
                    UIUtils.showToast(getContext(), "Sale saved!");
                    navigateBack();
                } else if (resource.status == Resource.Status.ERROR) {
                    DialogUtils.showInfoDialog(requireContext(), "Save Error", resource.message);
                }
            }
        });
    }

    private void showRefundDialog() {
        DialogUtils.showConfirmDialog(requireContext(), "Process Refund", 
            "Are you sure you want to process a refund for this sale?", () -> {
            Bundle args = new Bundle();
            args.putLong("saleId", viewModel.getSaleId());
            NavHostFragment.findNavController(this).navigate(R.id.nav_refund, args);
        });
    }

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

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