package ru.kayashov.bar.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.kayashov.bar.controller.dto.ingredient.IngredientResponseDto;
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
import ru.kayashov.bar.mapper.IngredientMapper;
import ru.kayashov.bar.model.Ingredient;
import ru.kayashov.bar.model.entity.BarEntity;
import ru.kayashov.bar.model.entity.CocktailEntity;
import ru.kayashov.bar.model.entity.IngredientEntity;
import ru.kayashov.bar.model.entity.ReceiptEntity;
import ru.kayashov.bar.model.entity.TypeEntity;
import ru.kayashov.bar.repository.BarEntityRepository;
import ru.kayashov.bar.repository.CocktailRepository;
import ru.kayashov.bar.repository.IngredientRepository;
import ru.kayashov.bar.repository.ReceiptRepository;
import ru.kayashov.bar.repository.TypeRepository;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class IngredientService {

    private final TypeRepository typeRepository;
    private final IngredientRepository repository;
    private final IngredientMapper mapper;
    private final BarEntityRepository barEntityRepository;
    private final IngredientRepository ingredientRepository;
    private final ReceiptRepository receiptRepository;
    private final CocktailRepository cocktailRepository;

    private TypeEntity findTypeByName(String name) {
        return typeRepository.findByName(name)
                .orElse(null);
    }

    /**
     * Запрос ингредиентов бара
     */
    public List<IngredientResponseDto> getAll() {
        List<IngredientEntity> ingredients = repository.findAll();
        log.info("По запросу найдено {} ингредиентов", ingredients.size());
        return mapper.mapIngredientsToDtoList(ingredients);
    }

    public List<IngredientSimpleResponseDto> getAllSimple() {
        List<IngredientEntity> ingredients = repository.findAll();
        log.info("По запросу найдено {} ингредиентов", ingredients.size());
        return mapper.mapIngredientsToSimpleDtoList(ingredients);
    }

    public IngredientEntity getIngredientById(Long id) {
        return repository.findById(id).orElseThrow();
    }

    public void changeBarIngredient(Long id, boolean isHave) {
        BarEntity bar = barEntityRepository.findByActiveTrue().orElseThrow();
        IngredientEntity ingredientEntity = getIngredientById(id);
        ingredientEntity.setIsHave(isHave);
        ingredientRepository.save(ingredientEntity);

        List<CocktailEntity> cocktails = ingredientEntity.getReceipts().stream().map(ReceiptEntity::getCocktail).toList();
        List<CocktailEntity> listForSave;
        if (isHave) {
            bar.getIngredients().add(ingredientEntity);
            listForSave = new ArrayList<>();
            for (CocktailEntity cocktail : cocktails) {
                if (cocktail.getReceipt().stream().map(ReceiptEntity::getIngredient).allMatch(IngredientEntity::getIsHave)) {
                    cocktail.setAllowed(true);
                    listForSave.add(cocktail);
                    log.info("Коктейль {} стал доступен", cocktail.getName());
                }
            }
        } else {
            bar.getIngredients().remove(ingredientEntity);
            listForSave = cocktails.stream().peek(c -> c.setAllowed(false)).toList();
            log.info("Коктейли {} пропали из доступа", listForSave);
        }

        cocktailRepository.saveAll(listForSave);
        barEntityRepository.save(bar);

        log.info("Ингредиент {} {}", ingredientEntity.getName(), isHave ? "добавлен в бар" : "удален из бара");
    }

    public boolean saveChange(IngredientResponseDto dto) {
        IngredientEntity entity;
        if (dto.getId() == null) {
            entity = new IngredientEntity();
        } else {
            entity = repository.findById(dto.getId())
                    .orElse(null);
            if (entity == null) {
                return false;
            }
        }

        entity.setName(dto.getName());
        entity.setDescription(dto.getDescription());
        entity.setAbv(dto.getAbv());
        entity.setAlcohol(dto.getAlcohol());

        TypeEntity type = findTypeByName(dto.getType());
//        if (type == null) {
//            return false;
//        }
        entity.setType(type);
        repository.save(entity);
        log.info("Ингредиент {} {}", entity.getName(), dto.getId() == null ? "создан" : "изменен");
        return true;
    }

    @Transactional
    public void removeIngredient(Long id) {
        IngredientEntity ingredient = ingredientRepository.findById(id).orElseThrow();

        List<CocktailEntity> cocktails = ingredient.getReceipts()
                .stream()
                .map(ReceiptEntity::getCocktail)
                .toList();

        receiptRepository.deleteAll(ingredient.getReceipts());
        cocktailRepository.deleteAll(cocktails);

        log.info("Удалены коктейли {}", cocktails.stream().map(c -> c.getId() + "-" + c.getName()).toList());
        repository.delete(ingredient);
        log.info("Удален ингредиент {}-{}", id, ingredient.getName());
    }
}
