package fr.eni.enchere.controllers;

import fr.eni.enchere.bll.ArticleService;
import fr.eni.enchere.bll.EnchereService;
import fr.eni.enchere.bll.UserService;
import fr.eni.enchere.bo.Article;
import fr.eni.enchere.bo.Enchere;
import fr.eni.enchere.bo.UserProfil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Controller()
@RequestMapping("/enchere")
public class EnchereController {

    @Autowired
    private EnchereService enchereService;
    private UserService userService;
    private ArticleService articleService;

    public EnchereController(EnchereService enchereService, UserService userService, ArticleService articleService) {
        this.enchereService = enchereService;
        this.userService = userService;
        this.articleService = articleService;
    }

    @PostMapping("/incEnchere")
    public String incEnchere(@ModelAttribute("enchere") Enchere enchere, @RequestParam("articleId") int articleId, BindingResult result, HttpSession session) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        enchere.setNoArticle(articleId);
        enchere.setNoUtilisateur(this.userService.utilisateurByName(authentication.getName()).getId());
        enchere.setDateEnchere(new Date());
        enchere.setMontantEnchere(enchere.getMontantEnchere());

        //Empeche une enchere inférieur au prix de base de l'article
        Article article = this.articleService.findArticleById(articleId);
        float articlePrice = article.getPrixInitial();
        float encherePrice = enchere.getMontantEnchere();
        if (encherePrice < articlePrice) {
            result.rejectValue("montantEnchere", "error.enchere", "Vous ne pouvez pas enchérir un montant inférieur au prix initial");
        }

        //Empeche une enchere inférieur au prix de la dernière enchère sur l'article
        List<Enchere> lastEnchere = this.enchereService.enchereByArticle(articleId);
        Optional<Float> maxMontantEnchere = lastEnchere.stream()
                .map(Enchere::getMontantEnchere) // Récupère seulement les montants d'enchère
                .max(Float::compareTo);
        if (maxMontantEnchere.isPresent() && encherePrice < maxMontantEnchere.get()) {
            result.rejectValue("montantEnchere", "error.enchere", "Vous ne pouvez pas enchérir un montant inférieur à la dernière enchère");
        }

        //Empeche l'enchère si les crédits du user sont inférieur au prix initial de l'article
        UserProfil userCredit = this.userService.utilisateurByName(authentication.getName());
        List<Enchere> encheres = this.enchereService.enchereByUser(userCredit.getId());
        double encheresSum = encheres.stream()
                .mapToDouble(ench -> ench.getMontantEnchere()) // Mappez chaque enchère à son montant
                .sum();
        if ((userCredit.getCredit() - encheresSum) < encherePrice) {
            result.rejectValue("montantEnchere", "error.enchere", "Vous ne pouvez pas enchérir si vous n'avez pas les fonds suffisant");
        }

        Optional<String> pseudoMaxEnchere = lastEnchere.stream()
                .max(Comparator.comparing(Enchere::getMontantEnchere)) // Comparaison basée sur le montant d'enchère
                .map(Enchere::getPseudoUtilisateur);
        if (pseudoMaxEnchere.isPresent() && pseudoMaxEnchere.get().equals(authentication.getName())) {
            result.rejectValue("montantEnchere", "error.enchere", "Vous ne pouvez pas enchèrir sur votre propre offre");
        }

        if (result.hasErrors()) {
            session.setAttribute("errors", result.getAllErrors());
            return "redirect:/article/show?id=" + articleId;
        }

        this.enchereService.setEnchere(enchere);
        return "redirect:/article/show?id=" + articleId;
    }

    @PostMapping("/enchereDone")
    public String enchereDone(@RequestParam("id") int id) {
        List<Enchere> listEncheres = this.enchereService.enchereByArticle(id);

        List<Enchere> encheres = listEncheres.stream()
                .sorted(Comparator.comparing(Enchere::getMontantEnchere).reversed())
                .collect(Collectors.toList());
        Optional<String> pseudoMaxEnchere = encheres.stream()
                .max(Comparator.comparing(Enchere::getMontantEnchere)) // Comparaison basée sur le montant d'enchère
                .map(Enchere::getPseudoUtilisateur);
        UserProfil user = this.userService.utilisateurByName(pseudoMaxEnchere.get());

        Optional<Float> maxMontantEnchere = listEncheres.stream()
                .map(Enchere::getMontantEnchere) // Récupère seulement les montants d'enchère
                .max(Float::compareTo);

        //setCredit user.
        float userCredit = user.getCredit();
        float newCredit = userCredit - maxMontantEnchere.get();
        this.userService.setCredit(newCredit, user.getId());

        //Delete enchere
        for (Enchere ench : listEncheres) {
            this.enchereService.deleteEnchere(ench.getId());
        }

        //Delete article
        this.articleService.setSellPrice(id, maxMontantEnchere.get());
        return "redirect:/enchere";
    }

}
