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.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.btnSaveSale.setVisibility(View.GONE);
            UIUtils.setViewsEnabled(false, binding.spinnerSaleStore, binding.spinnerSaleCustomer, binding.spinnerPaymentMethod);
        } else {
            loadData();
            setupAddItem();
        }

        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 void observeViewModel() {
        viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> {
            Long selectedStoreId = isStaff() ? tokenManager.getPrimaryStoreId() : -1L;
            SpinnerUtils.populateSpinner(requireContext(), binding.spinnerSaleStore, list,
                    DropdownDTO::getLabel, "-- Select Store --", selectedStoreId, DropdownDTO::getId);
            if (isStaff()) {
                binding.spinnerSaleStore.setEnabled(false);
            }
        });

        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();
        });
    }

    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 #" + saleId);
            binding.tvSaleDetailId.setText("ID: " + saleId);

            boolean isRefund = a.getBoolean("isRefund", false);
            if (isRefund) {
                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);
                
                // Show refund button only if it's not already a refund
                binding.btnRefundSale.setVisibility(isRefund ? 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: $" + sale.getTotalAmount());
                binding.tvSaleSubtotal.setText("$" + (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("-$" + 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("-$" + sale.getEmployeeDiscountAmount());
                } else {
                    binding.llEmployeeDiscount.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());
                    }
                }
            }
        });
    }

    private void setupAddItem() {
        binding.btnAddItem.setOnClickListener(v -> {
            if (!InputValidator.isSpinnerSelected(binding.spinnerSaleProduct, "Product")) return;
            if (!InputValidator.isPositiveInteger(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())) {
                    Toast.makeText(getContext(), "Product already added", Toast.LENGTH_SHORT).show();
                    return;
                }
            }

            viewModel.addToCart(new SaleDTO.SaleItemDTO(product.getProdId(), qty));
            binding.etSaleQuantity.setText("");
        });
    }

    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);
        }
    }

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

        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 ? "$" + price : "");

        row.addView(tvName);
        row.addView(tvQty);
        row.addView(tvPrice);
        binding.llSaleItems.addView(row);
    }

    private void updateTotal() {
        BigDecimal total = viewModel.calculateSubtotal();
        binding.tvSaleSubtotal.setText("$" + total);
        binding.tvSaleDetailTotal.setText("Total: $" + total);
    }

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

        if (viewModel.getCartItems().getValue() == null || viewModel.getCartItems().getValue().isEmpty()) {
            Toast.makeText(getContext(), "Add at least one item", Toast.LENGTH_SHORT).show();
            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);

        viewModel.createSale(dto).observe(getViewLifecycleOwner(), resource -> {
            if (resource != null) {
                setLoading(resource.status == Resource.Status.LOADING);
                if (resource.status == Resource.Status.SUCCESS) {
                    Toast.makeText(getContext(), "Sale saved!", Toast.LENGTH_SHORT).show();
                    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;
    }
}
