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

import fyloz.trial.ColorRecipesExplorer.model.Material;
import fyloz.trial.ColorRecipesExplorer.services.MaterialService;
import fyloz.trial.ColorRecipesExplorer.services.MaterialTypeService;
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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;

import java.util.stream.Collectors;

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

@Controller
public class MaterialEditorController {

    private MaterialService materialService;
    private MaterialTypeService materialTypeService;

    @Autowired
    public MaterialEditorController(MaterialService materialService, MaterialTypeService materialTypeService) {
        this.materialService = materialService;
        this.materialTypeService = materialTypeService;
    }

    /**
     * Affiche la page de tous les produits.
     * <p>
     * Modèle de la page:
     * - materials: La liste de tous les produits
     *
     * @param model Le Model injecté par Thymeleaf
     * @return La page à afficher.
     */
    @GetMapping(EDITOR_MATERIAL)
    public String listMaterials(Model model) {
        model.addAttribute(MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()));

        return EDITOR_MATERIAL;
    }

    /**
     * Affiche la page d'édition d'un produit.
     * La méthode requiert l'identifiant du produit à modifier dans l'URL.
     *
     * @param model      Le Model injecté par Thymeleaf
     * @param materialID L'identifiant du produit à modifier
     * @return La page à afficher.
     */
    @GetMapping(EDITOR_MATERIAL_SPECIFIC)
    public String showEditPage(Model model, @PathVariable int materialID) {
        Material material = materialService.getByID(materialID);

        if (material == null) {
            model.addAttribute(RESPONSE_ERROR, String.format(MATERIAL_NOT_FOUND, materialID));

            return listMaterials(model);
        }

        model.addAttribute(MATERIAL, material);
        model.addAttribute(MATERIAL_TYPES, materialTypeService.getAll());
        return EDITOR_MATERIAL_EDITOR;
    }

    /**
     * Affiche la page d'upload d'un fichier SIMDUT pour un produit
     * Cette méthode requiert l'identifiant du produit dans l'URL
     * <p>
     * Modèle de la page:
     * - materialID: Contient l'identifiant du produit
     *
     * @param model      Le Model injecté par Thymeleaf
     * @param materialID L'identifiant du produit à modifier le SIMDUT
     * @return La page à afficher.
     */
    @GetMapping(value = EDIT_MATERIAL_SIMDUT_SPECIFIC)
    public String chooseSIMDUTFile(Model model, @PathVariable int materialID) {
        model.addAttribute(MATERIAL_ID, materialID);

        return EDIT_MATERIAL_SIMDUT;
    }

    /**
     * Sauvegarde le fichier SIMDUT d'un produit.
     * <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 materialID L'identifiant du produit
     * @param simdut     Le fichier SIMDUT uploadé
     * @return La page à afficher.
     */
    @PostMapping(value = EDIT_MATERIAL_SIMDUT, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String saveSIMDUT(Model model, int materialID, MultipartFile simdut) {
        Material material = materialService.getByID(materialID);
        if (material == null) {
            model.addAttribute(RESPONSE_ERROR, MATERIAL_NOT_FOUND);
            return chooseSIMDUTFile(model, materialID);
        }

        if (!materialService.removeSimdut(material) || !materialService.addSimdut(simdut, material)) {
            model.addAttribute(RESPONSE_ERROR, ERROR_SAVING_SIMDUT);
            return chooseSIMDUTFile(model, materialID);
        }

        return "redirect:/material/editor/" + materialID;
    }

    /**
     * Permet à l'utilisateur de modifier un produit.
     * <p>
     * La modification échouera si:
     * - L'utilisateur n'est pas autorisé à exécuter cette action
     * - Il n'y a aucun produit avec l'identifiant passé en paramètre
     * - 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
     * - materialCode: Contient le code du produit mit à jour
     * <p>
     * REQUIERT UNE AUTORISATION
     *
     * @param model    Le Model injecté par Thymeleaf
     * @param material Le produit à mettre à jour
     * @return La page à afficher.
     */
    @PostMapping(value = EDITOR_MATERIAL, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public String saveEditedMaterial(Model model, Material material) {
        int materialID = material.getMaterialID();

        if (materialService.getByID(materialID) == null) {
            model.addAttribute(RESPONSE_ERROR, String.format(MATERIAL_NOT_FOUND, materialID));
        }

        if ((material = materialService.update(material)) != null) {
            model.addAttribute(MATERIAL_CODE, material.getMaterialCode());
        } else {
            model.addAttribute(RESPONSE_ERROR, ERROR_SAVING);
            return showEditPage(model, materialID);
        }

        return listMaterials(model);
    }
}
