package de.htwsaar.webshop.service.impl;

import de.htwsaar.webshop.model.ArticleModel;
import de.htwsaar.webshop.repository.ArticleRepository;
import de.htwsaar.webshop.repository.ReviewRepository;
import de.htwsaar.webshop.repository.entities.Article;
import de.htwsaar.webshop.repository.entities.Review;
import de.htwsaar.webshop.service.ArticleService;
import jakarta.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

@Service
@Slf4j
public class ArticleServiceImpl implements ArticleService {
    private final ArticleRepository articleRepository;
    private final ReviewRepository reviewRepository;

    @Autowired
    public ArticleServiceImpl(ArticleRepository articleRepository, ReviewRepository reviewRepository) {
        this.articleRepository = articleRepository;
        this.reviewRepository = reviewRepository;
    }

    @Override
    public List<Article> findAll() {
        return articleRepository.findAll();
    }

    @Override
    public Article findByUUID(UUID uuid) {
        return articleRepository.findArticleByUuid(uuid).orElse(null);
    }

    @Override
    public Article findByTitle(String title) {
        return articleRepository.findArticleByName(title).orElse(null);
    }

    @Override
    public Article findById(Long articleId) {
        return articleRepository.findArticleById(articleId).orElse(null);
    }

    @Override
    public void delete(Long id) {
        articleRepository.deleteById(id);
    }

    @Override
    public void delete(UUID uuid) {
        articleRepository.deleteByUuid(uuid);
    }

    @Override
    @Transactional
    public Article save(Article article) {
        article.setId(null);
        article.setUuid(UUID.randomUUID());
        return articleRepository.save(article);
    }

    @Override
    public double getRating(Long id) {
        return reviewRepository.streamReviewsByArticleId(id)
                .mapToInt(Review::getRating)
                .average()
                .orElse(-1);
    }

    @Override
    @Transactional
    public double getRating(UUID uuid) {
        return reviewRepository.streamReviewsByArticleId(
                articleRepository.findArticleByUuid(uuid).orElseThrow().getId()
        ).mapToInt(Review::getRating).average().orElse(-1);
    }

    @Override
    public ArticleModel from(Article article) {
        return new ArticleModel(
                article.getId(),
                article.getUuid(),
                article.getName(),
                article.getDescription(),
                article.getPrice100(),
                article.getDiscount100(),
                article.getStock(),
                article.getStockExpected(),
                article.getCategory(),
                calculateAverageRating(article.getReviews())
        );
    }

    private double calculateAverageRating(List<Review> reviews) {
        return reviews.stream()
                .mapToInt(Review::getRating)
                .average()
                .orElse(-1);
    }

    @Override
    public List<ArticleModel> from(List<Article> articles) {
        return articles.stream().map(this::from).toList();
    }
}
