package fyloz.trial.ColorRecipesExplorer.web.controller;

import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication;
import fyloz.trial.ColorRecipesExplorer.core.io.ImageHandler;
import fyloz.trial.ColorRecipesExplorer.model.Recipe;
import fyloz.trial.ColorRecipesExplorer.services.RecipeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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

@Controller
public class ImageFilesController {

    private RecipeService recipeService;

    @Autowired
    public ImageFilesController(RecipeService recipeService) {
        this.recipeService = recipeService;
    }

    /**
     * Récupère l'image voulue sous forme JPEG.
     *
     * @param image Le nom de l'image
     * @return L'image en JPEG.
     */
    @GetMapping(IMAGES_FILES)
    public ResponseEntity<byte[]> getImage(@PathVariable String image) {
        ImageHandler imageHandler = new ImageHandler(image, recipeService);

        byte[] content = imageHandler.readFile();
        if (content == null) return ResponseEntity.notFound().build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_JPEG);
        return new ResponseEntity<>(content, headers, HttpStatus.OK);
    }

    /**
     * Affiche la page pour ajouter une image pour une recette.
     * Cette méthode requiert l'identifiant de la recette dans l'URL.
     * <p>
     * Modèle de la page:
     * - recipeID: Contient l'identifiant de la recette
     *
     * @param model    Le Model injecté par Thymeleaf
     * @param recipeID L'identifiant de la recette
     * @return La page à afficher.
     */
    @GetMapping(ADD_IMAGE_SPECIFIC)
    public String showPage(Model model, @PathVariable int recipeID) {
        model.addAttribute(RECIPE_ID, recipeID);
        return ADD_IMAGE;
    }

    /**
     * Permet à l'utilisateur d'uploader une image.
     * <p>
     * L'upload échouera si:
     * - L'utilisateur n'est pas autorisé à exécuter cette action.
     * - La recette n'existe pas
     * - Une erreur est survenue lors de la création du fichier de l'image
     * - Une erreur est survenue lors du transfert de l'image vers le fichier
     * <p>
     * Modèle de la page:
     * - error: Contient le message d'erreur, s'il y a lieu
     * - recipeCode: Contient la couleur de la recette
     * - recipeID: Contient l'identifiant de la recette
     * <p>
     * REQUIERT UNE AUTORISATION
     *
     * @param model    Le Model injecté par Thymeleaf
     * @param recipeID L'identifiant de la recette
     * @param image    L'image uploadée
     * @return La page à afficher.
     */
    @PostMapping(ADD_IMAGE)
    public String addImage(Model model, int recipeID, MultipartFile image) {
        Recipe recipe = recipeService.getByID(recipeID);
        if (recipe == null) {
            model.addAttribute(RESPONSE_ERROR, RECIPE_NOT_FOUND);
            return showPage(model, recipeID);
        }

        ImageHandler imageHandler = new ImageHandler(recipe, recipeService);
        if (!imageHandler.createFile()) {
            model.addAttribute(RESPONSE_ERROR, ERROR_SAVING_IMAGE);
            return showPage(model, recipeID);
        }

        model.addAttribute(RECIPE_CODE, recipe.getRecipeCode());
        model.addAttribute(RECIPE_ID, recipe.getRecipeID());

        try {
            // Si je n'utilise pas le path, il cherche un fichier dans les tmp ?
            image.transferTo(new File(imageHandler.getFile().getAbsolutePath()));

            return "redirect:/" + EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(recipeID));
        } catch (IOException e) {
            ColorRecipesExplorerApplication.logger.error("Erreur inconnue lors de la création d'une image", e);
            model.addAttribute(RESPONSE_ERROR, ERROR_SAVING_IMAGE);
            return showPage(model, recipeID);
        }
    }

    /**
     * Permet à l'utilisateur de supprimer une image.
     * <p>
     * La suppression échouera si:
     * - L'utilisateur n'est pas autorisé à exécuter cette action
     * - Une erreur est survenue lors de la suppression du fichier
     * <p>
     * Réponse de la méthode:
     * - error: Contient le message d'erreur, s'il y a lieu
     * <p>
     * REQUIERT UNE AUTORISATION
     *
     * @param form Le formulaire contenant les informations sur l'opération
     * @return La réponse sous forme de Map (-> Json)
     */
    @PostMapping(value = DELETE_IMAGE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public Map<String, String> deleteImage(@RequestBody Map<String, String> form) {
        Map<String, String> response = new HashMap<>();

        ImageHandler imageHandler = new ImageHandler(form.get("image"), recipeService);
        if (!imageHandler.deleteFile()) {
            response.put(RESPONSE_ERROR, ERROR_SAVING_IMAGE);
        }

        return response;
    }
}
