ProductService.java

package com.ctrlbuy.webshop.service;

import com.ctrlbuy.webshop.model.Product;
import com.ctrlbuy.webshop.repository.ProductRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
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.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
@Transactional
public class ProductService {

    private final ProductRepository productRepository;

    // ================================
    // BEFINTLIGA METODER - OFÖRÄNDRADE
    // ================================

    /**
     * Hämtar alla produkter från databasen
     * FIXAT - explicit transaction och debugging
     */
    @Transactional(readOnly = true)
    public List<Product> getAllProducts() {
        log.info("🔍 DEBUGGING: Hämtar alla produkter från databas");

        try {
            List<Product> products = productRepository.findAll();
            log.info("🔍 DEBUGGING: Repository returnerade {} produkter", products.size());

            // Debug första produkterna
            if (!products.isEmpty()) {
                Product first = products.get(0);
                log.info("🔍 DEBUGGING: Första produkten: ID={}, Name={}, Category={}",
                        first.getId(), first.getName(), first.getCategory());
            } else {
                log.warn("🔍 DEBUGGING: Repository returnerade tom lista!");

                // Testa direct count
                long count = productRepository.count();
                log.warn("🔍 DEBUGGING: Repository count() returnerar: {}", count);
            }

            return products;
        } catch (Exception e) {
            log.error("🔍 DEBUGGING: Fel vid hämtning av produkter: {}", e.getMessage(), e);
            return List.of();
        }
    }

    /**
     * Hämtar alla produkter med paginering (för ProductController)
     * BEFINTLIG - använder befintlig databasstruktur
     */
    public Page<Product> findAllActive(Pageable pageable) {
        log.debug("Hämtar produkter med paginering: {}", pageable);

        // Använd repository proxy för "aktiva" produkter
        List<Product> activeProducts = productRepository.findActiveProductsProxy();

        // Konvertera till Page med manuell paginering
        int start = (int) pageable.getOffset();
        int end = Math.min((start + pageable.getPageSize()), activeProducts.size());

        List<Product> pageContent = start < activeProducts.size() ?
                activeProducts.subList(start, end) : List.of();

        return new PageImpl<>(pageContent, pageable, activeProducts.size());
    }

    /**
     * Hämtar populära produkter
     * UPPDATERAD - använder ID som proxy för popularitet
     */
    public List<Product> getPopularProducts() {
        log.debug("Hämtar populära produkter (top 8 baserat på ID)");
        Pageable pageable = PageRequest.of(0, 8);
        return productRepository.findRecentProductsAsPopular(pageable);
    }

    /**
     * Hämtar produkter efter kategori
     * BEFINTLIG - fungerar med nuvarande databas
     */
    public List<Product> getProductsByCategory(String category) {
        log.debug("Hämtar produkter i kategori: {}", category);
        return productRepository.findByCategory(category);
    }

    /**
     * Hämtar produkter efter kategori med paginering
     * BEFINTLIG - fungerar med nuvarande databas
     */
    public Page<Product> findByCategory(String category, Pageable pageable) {
        log.debug("Hämtar produkter i kategori {} med paginering", category);
        return productRepository.findByCategory(category, pageable);
    }

    /**
     * Hämtar en produkt baserat på dess ID
     * UPPDATERAD - kommer att räkna visningar när view_count läggs till
     */
    public Product getProductById(Long id) {
        log.debug("Hämtar produkt med ID: {}", id);
        Optional<Product> product = productRepository.findById(id);

        if (product.isPresent()) {
            Product p = product.get();
            // TODO: Implementera visningsräkning när view_count kolumn läggs till
            // p.incrementViewCount();
            // productRepository.save(p);
            log.debug("Hämtade produkt: {}", p.getName());
            return p;
        }

        return null;
    }

    /**
     * Hämtar en produkt baserat på dess ID (Optional version)
     * UPPDATERAD - kommer att räkna visningar när view_count läggs till
     */
    public Optional<Product> findById(Long id) {
        log.debug("Hämtar produkt (Optional) med ID: {}", id);
        Optional<Product> productOpt = productRepository.findById(id);

        if (productOpt.isPresent()) {
            Product product = productOpt.get();
            // TODO: Implementera visningsräkning när view_count kolumn läggs till
            // product.incrementViewCount();
            // productRepository.save(product);
            log.debug("Hämtade produkt: {}", product.getName());
        }

        return productOpt;
    }

    /**
     * Söker efter produkter baserat på nyckelord
     * BEFINTLIG - fungerar med nuvarande databas
     */
    public List<Product> searchProducts(String keyword) {
        log.debug("Söker produkter med nyckelord: {}", keyword);
        return productRepository.findByNameContainingOrDescriptionContainingIgnoreCase(keyword, keyword);
    }

    /**
     * Söker efter produkter med paginering
     * UPPDATERAD - använder ny Query-metod
     */
    public Page<Product> searchProducts(String keyword, Pageable pageable) {
        log.debug("Söker produkter med paginering för: {}", keyword);
        return productRepository.searchProducts(keyword, pageable);
    }

    /**
     * Hämtar alla kategorier
     * UPPDATERAD - använder optimerad Query
     */
    public List<String> getAllCategories() {
        log.debug("Hämtar alla kategorier");
        return productRepository.findDistinctCategories();
    }

    /**
     * Hämtar produkter inom ett visst prisintervall
     * BEFINTLIG - fungerar med nuvarande databas
     */
    public List<Product> getProductsByPriceRange(BigDecimal minPrice, BigDecimal maxPrice) {
        log.debug("Hämtar produkter inom prisintervall: {} - {}", minPrice, maxPrice);
        return productRepository.findByPriceBetween(minPrice, maxPrice);
    }

    /**
     * Inkrementerar visningsantalet för en produkt
     * TILLFÄLLIG - kommer att implementeras när view_count läggs till
     */
    public void incrementViewCount(Long productId) {
        log.debug("Visningsräkning för produkt: {} (väntar på view_count kolumn)", productId);
        // TODO: Implementera när view_count kolumn läggs till
        /*
        productRepository.findById(productId)
                .ifPresent(product -> {
                    product.incrementViewCount();
                    productRepository.save(product);
                    log.debug("Uppdaterade visningar för '{}' till {}",
                             product.getName(), product.getViewCount());
                });
        */
    }

    /**
     * Hämtar nyligen tillagda produkter
     * UPPDATERAD - använder ID som proxy för datum
     */
    public List<Product> getNewArrivals() {
        log.debug("Hämtar nyligen tillagda produkter (top 10 baserat på ID)");
        Pageable pageable = PageRequest.of(0, 10);
        return productRepository.findNewestProductsByIdProxy(pageable);
    }

    /**
     * Skapar eller uppdaterar en produkt
     * BEFINTLIG - fungerar med nuvarande databas
     */
    public Product saveProduct(Product product) {
        log.info("Sparar produkt: {}", product.getName());
        return productRepository.save(product);
    }

    /**
     * Tar bort en produkt baserat på dess ID
     * BEFINTLIG - fungerar med nuvarande databas
     */
    public void deleteProduct(Long id) {
        log.info("Tar bort produkt: {}", id);
        productRepository.deleteById(id);
    }

    /**
     * Debug-metod för att kontrollera produkter
     * UPPDATERAD - förbättrad statistik
     */
    public void debugProductCount() {
        long totalCount = productRepository.count();
        long inStockCount = productRepository.countInStockProducts();
        long outOfStockCount = productRepository.countOutOfStockProducts();

        System.out.println("=== PRODUCT DEBUG ===");
        System.out.println("Total products in database: " + totalCount);
        System.out.println("Products in stock: " + inStockCount);
        System.out.println("Products out of stock: " + outOfStockCount);

        if (totalCount > 0) {
            List<Product> sample = productRepository.findAll().stream().limit(3).toList();

            for (Product product : sample) {
                System.out.println("Sample product: ID=" + product.getId() +
                        ", Name=" + product.getName() +
                        ", Category=" + product.getCategory() +
                        ", Price=" + product.getPrice() +
                        ", Stock=" + product.getStockQuantity());
            }
        }
        System.out.println("===================");
    }

    // ================================
    // NYA METODER SOM FUNGERAR MED NUVARANDE DATABAS
    // ================================

    /**
     * Hämtar alla aktiva produkter (proxy-metod)
     */
    public List<Product> getAllActiveProducts() {
        log.debug("Hämtar alla 'aktiva' produkter (proxy)");
        return productRepository.findActiveProductsProxy();
    }

    /**
     * Hämtar produkter med paginering och sortering
     */
    public Page<Product> getActiveProducts(int page, int size, String sortBy, String sortDir) {
        log.debug("Hämtar produkter - sida: {}, storlek: {}, sortering: {} {}",
                page, size, sortBy, sortDir);

        Sort sort = sortDir.equalsIgnoreCase("desc") ?
                Sort.by(sortBy).descending() :
                Sort.by(sortBy).ascending();

        Pageable pageable = PageRequest.of(page, size, sort);

        // Använd findAll med sortering för nu
        return productRepository.findAll(pageable);
    }

    /**
     * Hämtar produkter per kategori (alias)
     */
    public List<Product> getActiveProductsByCategory(String category) {
        return getProductsByCategory(category);
    }

    /**
     * Hämta produkt utan att räkna visning
     */
    public Optional<Product> getProductByIdWithoutView(Long id) {
        log.debug("Hämtar produkt utan visningsräkning: {}", id);
        return productRepository.findById(id);
    }

    /**
     * Sök aktiva produkter (alias)
     */
    public List<Product> searchActiveProducts(String searchTerm) {
        return searchProducts(searchTerm);
    }

    /**
     * Hämta produkter på rea (tillfällig proxy-metod)
     */
    public List<Product> getProductsOnSale() {
        log.debug("Hämtar produkter på 'rea' (proxy baserat på nyckelord)");
        return productRepository.findSaleProductsProxy();
    }

    /**
     * Hämta populära produkter (med limit)
     */
    public List<Product> getPopularProducts(int limit) {
        log.debug("Hämtar {} populära produkter", limit);
        Pageable pageable = PageRequest.of(0, limit);
        return productRepository.findRecentProductsAsPopular(pageable);
    }

    /**
     * Hämta nya produkter (med limit)
     */
    public List<Product> getNewestProducts(int limit) {
        log.debug("Hämtar {} nyaste produkter", limit);
        Pageable pageable = PageRequest.of(0, limit);
        return productRepository.findNewestProductsByIdProxy(pageable);
    }

    /**
     * Hämta produkter med lågt lager
     */
    public List<Product> getLowStockProducts(int threshold) {
        log.debug("Hämtar produkter med lager under {}", threshold);
        return productRepository.findByStockQuantityLessThan(threshold);
    }

    // ================================
    // CRUD-OPERATIONER FÖR ADMIN
    // ================================

    public Product createProduct(Product product) {
        log.info("Skapar ny produkt: {}", product.getName());
        product.setId(null); // Säkerställ att det är en ny produkt
        return productRepository.save(product);
    }

    public Product updateProduct(Long id, Product updatedProduct) {
        log.info("Uppdaterar produkt med ID: {}", id);

        return productRepository.findById(id)
                .map(existingProduct -> {
                    updatedProduct.setId(id);
                    // TODO: Behåll timestamps när kolumnerna läggs till
                    return productRepository.save(updatedProduct);
                })
                .orElseThrow(() -> new RuntimeException("Produkt med ID " + id + " hittades inte"));
    }

    public void hardDeleteProduct(Long id) {
        log.warn("Permanent borttagning av produkt: {}", id);
        productRepository.deleteById(id);
    }

    // ================================
    // LAGERHANTERING
    // ================================

    public boolean updateStock(Long productId, Integer newQuantity) {
        log.info("Uppdaterar lager för produkt {} till {}", productId, newQuantity);

        return productRepository.findById(productId)
                .map(product -> {
                    product.setStockQuantity(newQuantity);
                    productRepository.save(product);
                    return true;
                })
                .orElse(false);
    }

    public boolean decreaseStock(Long productId, Integer quantity) {
        log.info("Minskar lager för produkt {} med {}", productId, quantity);

        return productRepository.findById(productId)
                .map(product -> {
                    if (product.getStockQuantity() >= quantity) {
                        product.setStockQuantity(product.getStockQuantity() - quantity);
                        productRepository.save(product);
                        return true;
                    }
                    log.warn("Otillräckligt lager för produkt {}. Finns: {}, Begärt: {}",
                            productId, product.getStockQuantity(), quantity);
                    return false;
                })
                .orElse(false);
    }

    // ================================
    // STATISTIK SOM FUNGERAR NU
    // ================================

    public long getTotalActiveProducts() {
        return productRepository.count(); // Alla produkter för nu
    }

    public long getTotalProductsOnSale() {
        return productRepository.findSaleProductsProxy().size(); // Proxy-metod
    }

    public BigDecimal getAveragePrice() {
        return productRepository.findAveragePrice();
    }

    // ================================
    // AVANCERAD SÖKNING OCH FILTRERING
    // ================================

    /**
     * Avancerad sökning med flera filter
     */
    public Page<Product> findProductsWithFilters(String category, BigDecimal minPrice,
                                                 BigDecimal maxPrice, Boolean inStock,
                                                 String searchTerm, Pageable pageable) {
        log.debug("Avancerad sökning med filter");
        return productRepository.findProductsWithFilters(category, minPrice, maxPrice,
                inStock, searchTerm, pageable);
    }

    /**
     * Hitta relaterade produkter
     */
    public List<Product> getRelatedProducts(String category, Long excludeId, int limit) {
        log.debug("Hämtar relaterade produkter i kategori: {}", category);
        Pageable pageable = PageRequest.of(0, limit);
        return productRepository.findRelatedProductsByCategory(category, excludeId, pageable);
    }

    // ================================
    // METODER SOM KOMMER ATT AKTIVERAS
    // När nya kolumner läggs till
    // ================================

    /*
    // DESSA METODER AKTIVERAS AUTOMATISKT NÄR KOLUMNERNA LÄGGS TILL:

    public Product setSalePrice(Long productId, BigDecimal salePrice) {
        // Implementeras när sale_price kolumn läggs till
    }

    public Product removeSalePrice(Long productId) {
        // Implementeras när sale_price kolumn läggs till
    }

    // Markera som inaktiv istället för att ta bort
    public void deleteProduct(Long id) {
        // Uppdateras för soft delete när is_active läggs till
    }
    */
}