package dev.fyloz.trial.colorrecipesexplorer.service.model;

import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsException;
import dev.fyloz.trial.colorrecipesexplorer.exception.model.ModelException;
import dev.fyloz.trial.colorrecipesexplorer.model.Material;
import dev.fyloz.trial.colorrecipesexplorer.model.MaterialSaveDto;
import dev.fyloz.trial.colorrecipesexplorer.model.MaterialType;
import dev.fyloz.trial.colorrecipesexplorer.model.MaterialUpdateDto;
import dev.fyloz.trial.colorrecipesexplorer.repository.MaterialRepository;
import dev.fyloz.trial.colorrecipesexplorer.service.AbstractJavaNamedService;
import dev.fyloz.trial.colorrecipesexplorer.service.files.SimdutService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class MaterialJavaService extends AbstractJavaNamedService<Material, MaterialRepository> {

    private MixQuantityService mixQuantityService;
    private SimdutService simdutService;

    public MaterialJavaService() {
        super(Material.class);
    }

    @Autowired
    public void setMaterialDao(MaterialRepository materialRepository) {
        this.repository = materialRepository;
    }

    @Autowired
    public void setMixQuantityService(MixQuantityService mixQuantityService) {
        this.mixQuantityService = mixQuantityService;
    }

    @Autowired
    public void setSimdutService(SimdutService simdutService) {
        this.simdutService = simdutService;
    }

    /**
     * Vérifie si des produits sont d'un type de produit
     *
     * @param materialType Le type de produit
     * @return Si des produits sont du type de produit
     */
    public boolean existsByMaterialType(MaterialType materialType) {
        return repository.existsByMaterialType(materialType);
    }

    /**
     * Vérifie si un produit est lié à un ou plusieurs mélanges.
     *
     * @param material Le produit à vérifier.
     * @return Si le produit est lié à d'autres mélanges.
     */
    public boolean isLinkedToMixes(Material material) {
        return mixQuantityService.existsByMaterial(material);
    }

    /**
     * Récupère tous les produits qui ne sont pas des types de mélange.
     *
     * @return Tous les produits qui ne sont pas des types de mélange
     */
    @NotNull
    public List<Material> getAllNotMixType() {
        return getAll()
                .stream()
                .filter(m -> !m.isMixType())
                .collect(Collectors.toList());
    }

    public Material save(MaterialSaveDto material) {
        if (existsByName(material.getName()))
            throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.NAME, material.getName());
        Material saved = save(material.toMaterial());
        if (material.getSimdutFile() != null && !material.getSimdutFile().isEmpty())
            simdutService.write(saved, material.getSimdutFile());
        return saved;
    }

    @Override
    public Material update(Material material) {
        Optional<Material> materialByName = findOptional(repository.findByName(material.getName()));
        if (materialByName.isPresent() && !Objects.equals(material.getId(), materialByName.get().getId()))
            throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.NAME, material.getName());

        return super.update(material);
    }

    public Material update(MaterialUpdateDto material) {
        simdutService.update(material.getSimdutFile(), material.toMaterial());
        return update(material.toMaterial());
    }

    @Override
    public void delete(Material material) {
        simdutService.delete(material);

        super.delete(material);
    }

}
