OrderService.java

package com.ctrlbuy.webshop.service;

import com.ctrlbuy.webshop.model.Cart;
import com.ctrlbuy.webshop.model.CartItem;
import com.ctrlbuy.webshop.model.Order;
import com.ctrlbuy.webshop.model.OrderItem;
import com.ctrlbuy.webshop.security.entity.User;
import com.ctrlbuy.webshop.repository.OrderRepository;
import com.ctrlbuy.webshop.security.repository.UserRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.Random;

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

    private final OrderRepository orderRepository;
    private final UserRepository userRepository;
    private final ProductService productService;
    private final EmailService emailService; // ✅ NYTT: Lägg till EmailService

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * Skapa beställning från checkout-formulär
     */
    public Order createOrder(Cart cart, String email, String firstName, String lastName,
                             String address, String city, String postalCode, String phone,
                             String notes, String paymentMethod, Authentication auth) {

        if (cart == null || cart.getItems().isEmpty()) {
            throw new RuntimeException("Kundvagnen är tom");
        }

        log.info("Skapar beställning från checkout för: {}", email);

        // Hämta användare om inloggad
        User user = null;
        if (auth != null && auth.isAuthenticated()) {
            Optional<User> userOpt = userRepository.findByUsername(auth.getName());
            user = userOpt.orElse(null);
        }

        // Beräkna totaler
        BigDecimal subtotal = cart.getTotalAmount();
        BigDecimal shipping = BigDecimal.valueOf(49.00);
        BigDecimal total = subtotal.add(shipping);

        // Generera ordernummer
        String orderNumber = generateOrderNumber();

        // Skapa beställning
        Order order = new Order();
        order.setUser(user);
        order.setOrderNumber(orderNumber);
        order.setTotalAmount(total.doubleValue());
        order.setStatus(Order.OrderStatus.PENDING);
        order.setOrderDate(LocalDateTime.now());

        // Leveransadress
        order.setDeliveryName(firstName + " " + lastName);
        order.setDeliveryAddress(address);
        order.setDeliveryCity(city);
        order.setDeliveryPostalCode(postalCode);
        order.setDeliveryPhone(phone);
        order.setPaymentMethod(paymentMethod);

        // Spara beställning först
        order = orderRepository.save(order);

        // Lägg till orderitems från cart
        for (CartItem cartItem : cart.getItems()) {
            OrderItem orderItem = new OrderItem();
            orderItem.setOrder(order);
            orderItem.setProduct(cartItem.getProduct());
            orderItem.setQuantity(cartItem.getQuantity());
            orderItem.setPrice(cartItem.getUnitPrice().doubleValue());
            orderItem.setProductName(cartItem.getProduct().getName());

            order.addOrderItem(orderItem);
        }

        // Spara igen med orderitems
        order = orderRepository.save(order);

        // ✅ NYTT: Skicka orderbekräftelse via e-post
        try {
            emailService.sendOrderConfirmation(order, user != null ? user.getEmail() : email);
            log.info("Orderbekräftelse skickad till: {}", user != null ? user.getEmail() : email);
        } catch (Exception e) {
            log.error("Kunde inte skicka orderbekräftelse för order {}: {}", orderNumber, e.getMessage());
            // Logga felet men låt inte det stoppa orderprocessen
        }

        log.info("Beställning skapad med ordernummer: {}", orderNumber);
        return order;
    }

    /**
     * Skapa ny beställning från kundvagn
     */
    public Order createOrderFromCart(User user, List<com.ctrlbuy.webshop.controller.CartController.CartItem> cartItems, OrderDetails orderDetails) {

        if (cartItems == null || cartItems.isEmpty()) {
            throw new RuntimeException("Kundvagnen är tom");
        }

        log.info("Skapar beställning för användare: {}", user.getEmail());

        // Beräkna totaler
        BigDecimal subtotal = cartItems.stream()
                .map(com.ctrlbuy.webshop.controller.CartController.CartItem::getTotalPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal shipping = subtotal.compareTo(new BigDecimal("499")) >= 0
                ? BigDecimal.ZERO
                : new BigDecimal("49");
        BigDecimal total = subtotal.add(shipping);

        // Generera ordernummer
        String orderNumber = generateOrderNumber();

        // Skapa beställning
        Order order = new Order();
        order.setUser(user);
        order.setOrderNumber(orderNumber);
        order.setTotalAmount(total.doubleValue());
        order.setStatus(Order.OrderStatus.PENDING);
        order.setOrderDate(LocalDateTime.now());

        // Leveransadress
        order.setDeliveryName(orderDetails.getDeliveryName());
        order.setDeliveryAddress(orderDetails.getDeliveryAddress());
        order.setDeliveryCity(orderDetails.getDeliveryCity());
        order.setDeliveryPostalCode(orderDetails.getDeliveryPostalCode());
        order.setDeliveryPhone(orderDetails.getDeliveryPhone());

        // Betalningsinformation
        order.setPaymentMethod(orderDetails.getPaymentMethod());

        // Spara beställning först
        order = orderRepository.save(order);

        // Lägg till orderitems
        for (com.ctrlbuy.webshop.controller.CartController.CartItem cartItem : cartItems) {
            OrderItem orderItem = new OrderItem();
            orderItem.setOrder(order);
            orderItem.setProduct(cartItem.getProduct());
            orderItem.setQuantity(cartItem.getQuantity());
            orderItem.setPrice(cartItem.getUnitPrice().doubleValue());
            orderItem.setProductName(cartItem.getProduct().getName());

            order.addOrderItem(orderItem);
        }

        // Spara igen med orderitems
        order = orderRepository.save(order);

        // ✅ NYTT: Skicka orderbekräftelse via e-post
        try {
            emailService.sendOrderConfirmation(order, user.getEmail());
            log.info("Orderbekräftelse skickad till: {}", user.getEmail());
        } catch (Exception e) {
            log.error("Kunde inte skicka orderbekräftelse för order {}: {}", orderNumber, e.getMessage());
            // Logga felet men låt inte det stoppa orderprocessen
        }

        log.info("Beställning skapad med ordernummer: {}", orderNumber);
        return order;
    }

    /**
     * Skapa beställning för icke-inloggad användare (gäst)
     */
    public Order createGuestOrder(List<com.ctrlbuy.webshop.controller.CartController.CartItem> cartItems, GuestOrderDetails guestDetails) {

        if (cartItems == null || cartItems.isEmpty()) {
            throw new RuntimeException("Kundvagnen är tom");
        }

        log.info("Skapar gästbeställning för: {}", guestDetails.getEmail());

        // Beräkna totaler
        BigDecimal subtotal = cartItems.stream()
                .map(com.ctrlbuy.webshop.controller.CartController.CartItem::getTotalPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal shipping = subtotal.compareTo(new BigDecimal("499")) >= 0
                ? BigDecimal.ZERO
                : new BigDecimal("49");
        BigDecimal total = subtotal.add(shipping);

        // Generera ordernummer
        String orderNumber = generateOrderNumber();

        // Skapa beställning utan User
        Order order = new Order();
        order.setOrderNumber(orderNumber);
        order.setTotalAmount(total.doubleValue());
        order.setStatus(Order.OrderStatus.PENDING);
        order.setOrderDate(LocalDateTime.now());

        // Leveransadress från gäst
        order.setDeliveryName(guestDetails.getFirstName() + " " + guestDetails.getLastName());
        order.setDeliveryAddress(guestDetails.getAddress());
        order.setDeliveryCity(guestDetails.getCity());
        order.setDeliveryPostalCode(guestDetails.getPostalCode());
        order.setDeliveryPhone(guestDetails.getPhone());

        // Betalningsinformation
        order.setPaymentMethod(guestDetails.getPaymentMethod());

        // Spara beställning först
        order = orderRepository.save(order);

        // Lägg till orderitems
        for (com.ctrlbuy.webshop.controller.CartController.CartItem cartItem : cartItems) {
            OrderItem orderItem = new OrderItem();
            orderItem.setOrder(order);
            orderItem.setProduct(cartItem.getProduct());
            orderItem.setQuantity(cartItem.getQuantity());
            orderItem.setPrice(cartItem.getUnitPrice().doubleValue());
            orderItem.setProductName(cartItem.getProduct().getName());

            order.addOrderItem(orderItem);
        }

        // Spara igen med orderitems
        order = orderRepository.save(order);

        // ✅ NYTT: Skicka orderbekräftelse via e-post för gäster
        try {
            emailService.sendOrderConfirmation(order, guestDetails.getEmail());
            log.info("Gäst-orderbekräftelse skickad till: {}", guestDetails.getEmail());
        } catch (Exception e) {
            log.error("Kunde inte skicka gäst-orderbekräftelse för order {}: {}", orderNumber, e.getMessage());
            // Logga felet men låt inte det stoppa orderprocessen
        }

        log.info("Gästbeställning skapad med ordernummer: {}", orderNumber);
        return order;
    }

    /**
     * Hitta beställning baserat på ordernummer och användare
     */
    public Order findByOrderNumberAndUser(String orderNumber, User user) {
        return orderRepository.findByOrderNumberAndUser(orderNumber, user);
    }

    /**
     * Hitta beställning endast baserat på ordernummer (för gäster)
     */
    public Order findByOrderNumber(String orderNumber) {
        return orderRepository.findByOrderNumber(orderNumber);
    }

    /**
     * Hitta alla beställningar för en användare
     */
    public List<Order> findByUser(User user) {
        return orderRepository.findByUserOrderByOrderDateDesc(user);
    }

    /**
     * Uppdatera orderstatus
     */
    public Order updateOrderStatus(Long orderId, Order.OrderStatus status) {
        Order order = orderRepository.findById(orderId)
                .orElseThrow(() -> new RuntimeException("Beställning hittades inte"));

        order.setStatus(status);
        Order updatedOrder = orderRepository.save(order);

        log.info("Orderstatus uppdaterad för beställning {}: {}", order.getOrderNumber(), status);
        return updatedOrder;
    }

    /**
     * ✅ UPPDATERAD: Generera enkelt ordernummer med löpnummer
     */
    private String generateOrderNumber() {
        // Hämta totalt antal ordrar och lägg till 1 för nästa nummer
        long nextOrderNumber = orderRepository.count() + 1;
        return String.format("CB%03d", nextOrderNumber);
    }

    /**
     * Hitta beställning baserat på ID
     */
    public Order findById(Long id) {
        return orderRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Beställning hittades inte"));
    }

    /**
     * Hitta beställning med orderItems (för att undvika LazyInitializationException)
     */
    @Transactional(readOnly = true)
    public Order findOrderWithItemsById(Long orderId) {
        try {
            return entityManager.createQuery(
                            "SELECT o FROM Order o LEFT JOIN FETCH o.orderItems WHERE o.id = :orderId",
                            Order.class)
                    .setParameter("orderId", orderId)
                    .getSingleResult();
        } catch (Exception e) {
            log.error("Kunde inte hämta beställning med ID: {}", orderId, e);
            return null;
        }
    }

    /**
     * Alla beställningar (admin)
     */
    public List<Order> findAll() {
        return orderRepository.findAllByOrderByOrderDateDesc();
    }

    /**
     * Räkna antal beställningar för användare
     */
    public Long countOrdersByUser(User user) {
        return orderRepository.countByUser(user);
    }

    // ========================================
    // NYA METODER FÖR ORDERHISTORIK
    // ========================================

    /**
     * Hämta orders med paginering för orderhistorik
     */
    public Page<Order> getOrdersByUserWithPagination(User user, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("orderDate").descending());
        return orderRepository.findByUser(user, pageable);
    }

    /**
     * Hämta specifik order för användare (säkerhetscheck)
     */
    public Optional<Order> getOrderByIdAndUser(Long orderId, User user) {
        return orderRepository.findByIdAndUser(orderId, user);
    }

    /**
     * Hämta order via ordernummer och användare (säkerhetscheck) - wrapprar befintlig metod
     */
    public Optional<Order> getOrderByOrderNumberAndUser(String orderNumber, User user) {
        Order order = findByOrderNumberAndUser(orderNumber, user);
        return Optional.ofNullable(order);
    }

    /**
     * Beräkna total summa för alla orders av användare
     */
    public Double getTotalSpentByUser(User user) {
        return orderRepository.sumTotalAmountByUser(user);
    }

    /**
     * Hämta senaste order för användare
     */
    public Optional<Order> getLatestOrderByUser(User user) {
        List<Order> orders = findByUser(user); // Använder befintlig metod
        return orders.isEmpty() ? Optional.empty() : Optional.of(orders.get(0));
    }

    /**
     * Hämta orders för användare (orderhistorik - använder befintlig metod)
     */
    public List<Order> getOrdersByUser(User user) {
        return findByUser(user); // Använder din befintliga metod
    }

    // DTO klasser för beställningsdata
    @lombok.Data
    @lombok.NoArgsConstructor
    @lombok.AllArgsConstructor
    public static class OrderDetails {
        private String deliveryName;
        private String deliveryAddress;
        private String deliveryCity;
        private String deliveryPostalCode;
        private String deliveryPhone;
        private String paymentMethod;
    }

    @lombok.Data
    @lombok.NoArgsConstructor
    public static class GuestOrderDetails {
        private String firstName;
        private String lastName;
        private String email;
        private String phone;
        private String address;
        private String city;
        private String postalCode;
        private String paymentMethod;
    }
}