package fyloz.trial.ColorRecipesExplorer.web.controller;

import fyloz.trial.ColorRecipesExplorer.model.Mix;
import fyloz.trial.ColorRecipesExplorer.model.Recipe;
import fyloz.trial.ColorRecipesExplorer.services.MixService;
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.web.bind.annotation.*;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

@Controller
public class RecipeExplorerController {

    private RecipeService recipeService;
    private MixService mixService;

    @Autowired
    public RecipeExplorerController(RecipeService recipeService, MixService mixService) {
        this.recipeService = recipeService;
        this.mixService = mixService;
    }

    /**
     * Affiche la recette.
     * Cette méthode requiert l'identifiant de la recette à affiche dans l'URL.
     * <p>
     * Modèle de la page:
     * - error: Contient le message d'erreur, s'il y a lieu
     * - recipe: Contient la recette
     * - mixes: Contient les mélanges associées à la recette
     * - images: Contient la liste des noms des images associées à la recette
     *
     * @param model    Le Model injecté par Thymeleaf
     * @param recipeID L'identifiant de la recette
     * @return La page à afficher.
     */
    @GetMapping(EXPLORER_RECIPE_SPECIFIC)
    public String showRecipe(Model model, @PathVariable int recipeID) {
        Recipe recipe = recipeService.getByID(recipeID);

        if (recipe == null) {
            model.addAttribute(RESPONSE_ERROR, String.format(RECIPE_NOT_FOUND, recipeID));
            return INDEX;
        }

        List<Mix> mixes = recipe.getRecipeMixes();
        mixes.sort(Comparator.comparing(Mix::getMixID));

        model.addAttribute(RECIPE, recipe);
        model.addAttribute(MIXES, mixes);
        model.addAttribute("images", recipeService.getImageFiles(recipe));

        return EXPLORER_RECIPE;
    }

    /**
     * Sauvegarde les informations de la recette.
     * <p>
     * Certaines parties de la sauvegarde échouera si:
     * - La recette n'existe pas
     * - Un des mélanges n'existe pas
     * - Un des mélanges n'est pas associé à la recette
     * <p>
     * Réponse de la méthode:
     * - error: Contient le message d'erreur, s'il y a lieu
     * - success: Contient le message à afficher lors du succès de la méthode
     *
     * @param form Le formulaire contenant les informations de la recette
     * @return La réponse sous forme de Map (-> Json)
     */
    @PostMapping(value = EXPLORER_RECIPE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public Map<String, String> saveRecipeInformations(@RequestBody Map<String, Object> form) {
        int recipeID = Integer.parseInt(form.get("recipeID").toString());
        Map<String, String> location = (Map<String, String>) form.get("locations");
        String note = form.get("note").toString();

        Map<String, String> response = new HashMap<>();

        Recipe recipe = recipeService.getByID(recipeID);
        if (recipe == null) {
            response.put(RESPONSE_ERROR, String.format(RECIPE_NOT_FOUND, recipeID));
        } else {
            recipe.setNote(note);
            recipeService.save(recipe);
        }

        for (String mixIDStr : location.keySet()) {
            int mixID = Integer.parseInt(mixIDStr);

            Mix mix = mixService.getByID(mixID);
            if (mix == null) {
                response.put(RESPONSE_ERROR, String.format(MIX_NOT_FOUND, mixID));
            } else if (mix.getRecipe().getRecipeID() != recipeID) {
                response.put(RESPONSE_ERROR, String.format(MIX_NOT_ASSOCIATED_WITH_RECIPE, mixID, recipeID));
            } else {
                mix.setLocation(location.get(mixIDStr));
                mixService.update(mix);
            }
        }

        if (response.get(RESPONSE_ERROR) == null) {
            response.put(RESPONSE_SUCCESS, SUCCESS_SAVING_RECIPE_INFORMATIONS);
        }

        return response;
    }
}
