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

import fyloz.trial.ColorRecipesExplorer.model.Material;
import fyloz.trial.ColorRecipesExplorer.model.Mix;
import fyloz.trial.ColorRecipesExplorer.model.MixType;
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 static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*;
import static fyloz.trial.ColorRecipesExplorer.web.StringBank.*;

@Controller
public class MixEditorController {

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

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

    /**
     * Affiche la page d'édition d'un mélange.
     * Cette méthode requiert l'identifiant du mélange à modifier dans l'URL.
     *
     * @param model Le Model injecté par Thymeleaf
     * @param mixID L'identifiant du mélange à modifier
     * @return La page à afficher.
     */
    @GetMapping(EDITOR_MIX_SPECIFIC)
    public String showPage(Model model, @PathVariable int mixID) {
        Mix mix = mixService.getByID(mixID);

        // Renvoie l'utilisateur à la page d'édition des recettes si le mélange n'est pas trouvé
        if (mix == null) {
            return "redirect:/" + EDITOR_RECIPE;
        }

        List<Material> materials = new ArrayList<>();
        List<MixType> associatedMixTypes = recipeService.getAssociatedMixesTypes(mix.getRecipe());
        for (Material material : materialService.getAll()) {
            if (!material.isMixType() || (!mix.getMixType().getMaterial().equals(material) && associatedMixTypes.contains(mixTypeService.getByMaterial(material)))) {
                materials.add(material);
            }
        }

        model.addAttribute(MIX, mix);
        model.addAttribute("mixJson", mixService.asJson(mix));
        model.addAttribute(RECIPE_CODE, mix.getRecipe().getRecipeCode());
        model.addAttribute("materialsJson", materialService.asJson(materials));

        return EDITOR_MIX_SPECIFIC.replaceAll("/\\{" + MIX_ID + "}", "");
    }

    /**
     * Permet à l'utilisateur de modifier un mélange.
     * <p>
     * La mise à jour échouera si:
     * - L'utilisateur n'est pas autorisé à exécuter cette action
     * - Le mélange n'existe pas
     * - Un des produits n'existe pas
     * - Une erreur est survenue lors de la mise à jour dans la base de données
     * <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  Le formulaire du mélange entré par l'utilisateur
     * @return La page à afficher.
     */
    @PostMapping(value = EDITOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public String saveMix(Model model, @RequestBody MultiValueMap<String, String> form) {
        int mixID = Integer.parseInt(form.getFirst(MIX_ID));

        Mix mix = mixService.getByID(mixID);
        if (mix == null) {
            model.addAttribute(RESPONSE_ERROR, String.format(MIX_NOT_FOUND, mixID));
            return showPage(model, mixID);
        }

        List<Integer> materials = new ArrayList<>();
        List<Float> quantities = new ArrayList<>();

        for (String key : form.keySet()) {
            String value = form.getFirst(key);

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

        if (!mixService.edit(mix, materials, quantities)) {
            model.addAttribute(RESPONSE_ERROR, ERROR_SAVING);
            return showPage(model, mixID);
        }

        return "redirect:/" + EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(mix.getRecipe().getRecipeID()));
    }

    @GetMapping(REMOVER_MIX_SPECIFIC)
    public String deleteMix(Model model, @PathVariable int mixID) {
        Mix mix = mixService.getByID(mixID);
        if (mix == null) {
            model.addAttribute(RESPONSE_ERROR, MIX_NOT_FOUND);
            return showPage(model, mixID);
        }

        if (!mixService.deleteMix(mix)) {
            model.addAttribute(RESPONSE_ERROR, ERROR_SAVING);
            return showPage(model, mixID);
        }

        return "redirect:/" + EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(mix.getRecipe().getRecipeID()));
    }
}
