package fyloz.trial.ColorRecipesExplorer.web.controller.creators;

import fyloz.trial.ColorRecipesExplorer.model.Material;
import fyloz.trial.ColorRecipesExplorer.model.MixType;
import fyloz.trial.ColorRecipesExplorer.model.Recipe;
import fyloz.trial.ColorRecipesExplorer.services.MaterialService;
import fyloz.trial.ColorRecipesExplorer.services.MixService;
import fyloz.trial.ColorRecipesExplorer.services.MixTypeService;
import fyloz.trial.ColorRecipesExplorer.services.RecipeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*;
import static fyloz.trial.ColorRecipesExplorer.web.StringBank.*;

@Controller
public class MixCreatorController {

    private MixService mixService;
    private RecipeService recipeService;
    private MaterialService materialService;
    private MixTypeService mixTypeService;

    @Autowired
    public MixCreatorController(MixService mixService, RecipeService recipeService, MaterialService materialService, MixTypeService mixTypeService) {
        this.mixService = mixService;
        this.recipeService = recipeService;
        this.materialService = materialService;
        this.mixTypeService = mixTypeService;
    }

    /**
     * Affiche la page de création d'un mélange.
     * Cette méthode requiert l'identifiant d'une recette dans l'URL.
     *
     * @param model    Le Model injecté par Thymeleaf
     * @param recipeID L'identifiant de la recette
     * @return La page à afficher.
     */
    @GetMapping(CREATOR_MIX_SPECIFIC)
    public String showCreationPage(Model model, @PathVariable int recipeID) {
        Recipe recipe = recipeService.getByID(recipeID);
        if (recipe == null) {
            return "redirect:/" + EDITOR_RECIPE;
        }

        List<MixType> associatedMixTypes = recipeService.getAssociatedMixesTypes(recipe);
        // Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette
        List<Material> materials = materialService.getAll().stream().filter(m -> !m.isMixType() || associatedMixTypes.contains(mixTypeService.getByMaterial(m))).collect(Collectors.toList());

        model.addAttribute(RECIPE, recipe);
        model.addAttribute(MATERIALS, materials);
        model.addAttribute("materialsJson", materialService.asJson(materials)); // Ajoute les matériaux sous forme de JSON pour utiliser la liste en Javascript

        return CREATOR_MIX;
    }

    /**
     * Permet à l'utilisateur de créer un mélange.
     * <p>
     * La création échouera si:
     * - L'utilisateur n'est pas autorisé à exécuter cette action
     * - La recette n'existe pas
     * - Un des produits n'existe pas
     * - Une erreur est survenue lors de la sauvegarde du type de mélange
     * - Une erreur est survenue lors de la sauvegarde du mélange
     * <p>
     * Modèle de la page:
     * - error: Contient le message d'erreur, s'il y a lieu
     * <p>
     * REQUIERT UNE AUTORISATION
     *
     * @param model Le Model injecté par Thymeleaf
     * @param form  La formulaire du mélange entré par l'utilisateur
     * @return La page à afficher.
     */
    @PostMapping(value = CREATOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public String createMix(Model model, @RequestBody MultiValueMap<String, String> form) {
        String mixTypeName = form.getFirst(MIX_TYPE);
        int recipeID = Integer.parseInt(form.getFirst(RECIPE_ID));

        List<Integer> materials = new ArrayList<>();
        List<Float> quantities = new ArrayList<>();
        // Trie les valeurs du formulaire de création du mélange
        for (String key : form.keySet()) {
            String value = form.getFirst(key);

            if (key.startsWith("product")) materials.add(Integer.parseInt(value));
            else if (key.startsWith("quantity") && !value.isEmpty()) quantities.add(Float.parseFloat(value));
        }

        Recipe recipe = recipeService.getByID(recipeID);
        if (recipe == null) {
            model.addAttribute(RESPONSE_ERROR, String.format(RECIPE_NOT_FOUND, recipeID));
            return EDITOR_RECIPE;
        }

        MixType mixType = mixTypeService.createByName(mixTypeName);
        if (mixType == null) {
            model.addAttribute(RESPONSE_ERROR, ERROR_SAVING);
            return EDITOR_RECIPE;
        } else if (recipeService.getAssociatedMixesTypes(recipe).contains(mixType)) {
            model.addAttribute(RESPONSE_ERROR, MIX_TYPE_ALREADY_USED);
            return EDITOR_RECIPE;
        }

        String errorMessage = mixService.create(materials, quantities, recipe, mixType);
        if (errorMessage != null) {
            model.addAttribute(RESPONSE_ERROR, errorMessage);
            return showCreationPage(model, recipeID);
        }

        return "redirect:/" + EDITOR_RECIPE_SPECIFIC.replaceAll("\\{" + RECIPE_ID + "}", String.valueOf(recipeID));
    }
}
