package com.kalyshev.yan.coffee.service;

import com.kalyshev.yan.coffee.controller.CoffeeDto;
import com.kalyshev.yan.coffee.model.Coffee;
import com.kalyshev.yan.coffee.repository.CoffeeNotFoundException;
import com.kalyshev.yan.coffee.repository.CoffeeRepository;
import com.kalyshev.yan.user.repository.UserNotFoundException;
import com.kalyshev.yan.util.validation.ValidatorUtil;
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 org.springframework.util.StringUtils;

import java.util.List;
import java.util.Optional;

@Service
public class CoffeeService {
    private final CoffeeRepository coffeeRepository;
    private final ValidatorUtil validatorUtil;
    public CoffeeService(CoffeeRepository coffeeRepository,
                          ValidatorUtil validatorUtil) {
        this.coffeeRepository = coffeeRepository;
        this.validatorUtil = validatorUtil;
    }
    @Transactional
    public Coffee addCoffee(String name, Double cost, String ingredients) {
        if (!StringUtils.hasText(name)) {
            throw new IllegalArgumentException("Coffee name is null or empty");
        }
        if (cost <= 0.0) {
            throw new IllegalArgumentException("Coffee cost is null or empty or negative");
        }
        final Coffee coffee = new Coffee(name, cost, ingredients);
        validatorUtil.validate(coffee);
        return coffeeRepository.save(coffee);
    }
    @Transactional(readOnly = true)
    public Coffee findCoffee(Long id) {
        final Optional<Coffee> coffee = coffeeRepository.findById(id);
        return coffee.orElseThrow(() -> new CoffeeNotFoundException(id));
    }
    @Transactional(readOnly = true)
    public List<CoffeeDto> findAllCoffees(int pageNo, int pageSize, String sortBy, String sortDir) {
        Sort sort = sortDir.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortBy).ascending()
                : Sort.by(sortBy).descending();

        // create Pageable instance
        Pageable pageable = PageRequest.of(pageNo, pageSize, sort);

        Page<Coffee> coffees = coffeeRepository.findAll(pageable);

        // get content for page object
        List<Coffee> listOfCoffees = coffees.getContent();

        List<CoffeeDto> content = listOfCoffees.stream()
                .map(CoffeeDto::new)
                .toList();

        return content;
    }
    @Transactional
    public Coffee updateCoffee(Long id, String name, Double cost, String ingredients) {
        final Coffee currentCoffee = findCoffee(id);
        if (StringUtils.hasText(name)) {
            currentCoffee.setName(name);
        }
        if (cost > 0.0) {
            currentCoffee.setCost(cost);
        }
        if (StringUtils.hasText(ingredients)) {
            currentCoffee.setIngredients(ingredients);
        }
        validatorUtil.validate(currentCoffee);
        return coffeeRepository.save(currentCoffee);
    }
    @Transactional
    public Coffee deleteCoffee(Long id) {
        final Coffee currentCoffee = findCoffee(id);
        coffeeRepository.delete(currentCoffee);
        return currentCoffee;
    }
    @Transactional
    public void deleteAllCoffees() {
        coffeeRepository.deleteAll();
    }
}