package fyloz.trial.ColorRecipesExplorer.services;

import fyloz.trial.ColorRecipesExplorer.dao.MixDao;
import fyloz.trial.ColorRecipesExplorer.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static fyloz.trial.ColorRecipesExplorer.web.StringBank.ERROR_SAVING;
import static fyloz.trial.ColorRecipesExplorer.web.StringBank.MATERIAL_NOT_FOUND;

@Service
public class MixService extends GenericService<Mix> {

    private MaterialService materialService;
    private MixQuantityService mixQuantityService;

    @Autowired
    public MixService(MixDao mixDao, MaterialService materialService, MixQuantityService mixQuantityService) {
        super(mixDao);
        this.materialService = materialService;
        this.mixQuantityService = mixQuantityService;
    }

    /**
     * Crée un mélange, ainsi que tous ses sous-éléments.
     * <p>
     * materials & quantities doivent avoir le même ordre.
     *
     * @param materials  La liste des identifiants des matériaux
     * @param quantities La liste des quantités de matériaux
     * @param recipe     La recette associée au mélange
     * @param mixType    Le type du mélange
     * @return Le message d'erreur, s'il y a lieu
     */
    @Transactional
    public String create(List<Integer> materials, List<Float> quantities, Recipe recipe, MixType mixType) {
        // Crée le mélange en premier pour avoir accès à son ID pour les autres éléments
        Mix mix = new Mix(recipe, mixType, null);

        if ((mix = save(mix)) != null) {
            List<MixQuantity> mixQuantities = createMixQuantities(mix, materials, quantities);
            if (mixQuantities == null) return MATERIAL_NOT_FOUND;

            if (mixQuantityService.saveAll(mixQuantities)) return null;
        }

        return ERROR_SAVING;
    }

    /**
     * Modifie un mélange, ainsi que ses sous-éléments.
     * <p>
     * materials & quantities doivent avoir le même ordre.
     *
     * @param mix        Le mélange à modifier
     * @param materials  La liste des identifiants des matériaux
     * @param quantities La liste des quantités de matériaux
     * @return Si le mélange a été modifier.
     */
    public boolean edit(Mix mix, List<Integer> materials, List<Float> quantities) {
        List<MixQuantity> mixQuantities = createMixQuantities(mix, materials, quantities);
        if (mixQuantities == null) return false;

        // Supprime les anciens MixQuantity pour éviter les doublons et les entrées inutiles dans la base de données
        if (!mixQuantityService.deleteAll(mix.getMixQuantities())) {
            return false;
        }

        return mixQuantityService.saveAll(mixQuantities);
    }

    public boolean deleteMix(Mix mix) {
        if (mixQuantityService.deleteAll(mix.getMixQuantities())) {
            return super.delete(mix);
        }

        return false;
    }

    /**
     * Crée une liste de MixQuantity, pour la création d'un mélange
     *
     * @param mix        Le mélange associé aux MixQuantity
     * @param materials  Les matériaux
     * @param quantities Les quantités
     * @return La liste des MixQuantity créés.
     */
    private List<MixQuantity> createMixQuantities(Mix mix, List<Integer> materials, List<Float> quantities) {
        List<MixQuantity> mixQuantities = new ArrayList<>();

        int i = 0;
        for (int materialID : materials) {
            Material material = materialService.getByID(materialID);

            if (material == null) {
                return null;
            }

            float associatedQuantity = quantities.get(i);

            MixQuantity quantity = new MixQuantity(mix, material, associatedQuantity);
            mixQuantities.add(quantity);

            i++;
        }

        return mixQuantities;
    }
}
