package com.petshop.backend.service;

import com.petshop.backend.dto.productsupplier.BulkDeleteProductSupplierRequest;
import com.petshop.backend.dto.productsupplier.ProductSupplierRequest;
import com.petshop.backend.dto.productsupplier.ProductSupplierResponse;
import com.petshop.backend.entity.Product;
import com.petshop.backend.entity.ProductSupplier;
import com.petshop.backend.entity.Supplier;
import com.petshop.backend.exception.ResourceNotFoundException;
import com.petshop.backend.repository.ProductRepository;
import com.petshop.backend.repository.ProductSupplierRepository;
import com.petshop.backend.repository.SupplierRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class ProductSupplierService {

    private final ProductSupplierRepository productSupplierRepository;
    private final ProductRepository productRepository;
    private final SupplierRepository supplierRepository;

    public ProductSupplierService(ProductSupplierRepository productSupplierRepository, ProductRepository productRepository, SupplierRepository supplierRepository) {
        this.productSupplierRepository = productSupplierRepository;
        this.productRepository = productRepository;
        this.supplierRepository = supplierRepository;
    }

    public Page<ProductSupplierResponse> getAllProductSuppliers(String query, Long productId, Long supplierId, Pageable pageable) {
        String normalizedQuery = normalizeFilter(query);
        Pageable mappedPageable = mapSortProperties(pageable);
        Page<ProductSupplier> productSuppliers = productSupplierRepository.searchProductSuppliers(normalizedQuery, productId, supplierId, mappedPageable);
        return productSuppliers.map(this::mapToResponse);
    }

    public ProductSupplierResponse getProductSupplierById(Long productId, Long supplierId) {
        ProductSupplier.ProductSupplierId id = new ProductSupplier.ProductSupplierId(productId, supplierId);
        ProductSupplier productSupplier = productSupplierRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException(
                    "ProductSupplier not found with productId: " + productId + " and supplierId: " + supplierId));
        return mapToResponse(productSupplier);
    }

    @Transactional
    public ProductSupplierResponse createProductSupplier(ProductSupplierRequest request) {
        Product product = productRepository.findById(request.getProductId())
                .orElseThrow(() -> new ResourceNotFoundException("Product not found with id: " + request.getProductId()));

        Supplier supplier = supplierRepository.findById(request.getSupplierId())
                .orElseThrow(() -> new ResourceNotFoundException("Supplier not found with id: " + request.getSupplierId()));

        ProductSupplier productSupplier = new ProductSupplier();
        productSupplier.setProduct(product);
        productSupplier.setSupplier(supplier);
        productSupplier.setCost(request.getCost());

        productSupplier = productSupplierRepository.save(productSupplier);
        return mapToResponse(productSupplier);
    }

    @Transactional
    public ProductSupplierResponse updateProductSupplier(Long productId, Long supplierId, ProductSupplierRequest request) {
        ProductSupplier.ProductSupplierId id = new ProductSupplier.ProductSupplierId(productId, supplierId);
        ProductSupplier productSupplier = productSupplierRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException(
                    "ProductSupplier not found with productId: " + productId + " and supplierId: " + supplierId));

        productSupplier.setCost(request.getCost());

        productSupplier = productSupplierRepository.save(productSupplier);
        return mapToResponse(productSupplier);
    }

    @Transactional
    public void deleteProductSupplier(Long productId, Long supplierId) {
        ProductSupplier.ProductSupplierId id = new ProductSupplier.ProductSupplierId(productId, supplierId);
        if (!productSupplierRepository.existsById(id)) {
            throw new ResourceNotFoundException(
                "ProductSupplier not found with productId: " + productId + " and supplierId: " + supplierId);
        }
        productSupplierRepository.deleteById(id);
    }

    @Transactional
    public void bulkDeleteProductSuppliers(BulkDeleteProductSupplierRequest request) {
        request.getKeys().forEach(key -> {
            ProductSupplier.ProductSupplierId id = new ProductSupplier.ProductSupplierId(
                key.getProductId(), key.getSupplierId());
            productSupplierRepository.deleteById(id);
        });
    }

    private String normalizeFilter(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }

    private Pageable mapSortProperties(Pageable pageable) {
        if (pageable.getSort().isUnsorted()) {
            return pageable;
        }

        List<Sort.Order> orders = new ArrayList<>();
        for (Sort.Order order : pageable.getSort()) {
            String property = order.getProperty();
            if ("productName".equalsIgnoreCase(property)) {
                orders.add(new Sort.Order(order.getDirection(), "product.prodName"));
            } else if ("supplierName".equalsIgnoreCase(property)) {
                orders.add(new Sort.Order(order.getDirection(), "supplier.supCompany"));
            } else {
                orders.add(order);
            }
        }
        return PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.by(orders));
    }

    private ProductSupplierResponse mapToResponse(ProductSupplier productSupplier) {
        return new ProductSupplierResponse(
            productSupplier.getProduct().getProdId(),
            productSupplier.getProduct().getProdName(),
            productSupplier.getSupplier().getSupId(),
            productSupplier.getSupplier().getSupCompany(),
            productSupplier.getCost(),
            productSupplier.getCreatedAt(),
            productSupplier.getUpdatedAt()
        );
    }
}
