package com.astalange.web.controller;

import com.astalange.core.entity.Dotation;
import com.astalange.core.repository.DotationRepository;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;
import jakarta.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import java.time.LocalDate;

import com.astalange.core.service.DotationService;
import com.astalange.core.repository.SaisonRepository;
import com.astalange.core.entity.Saison;

import com.astalange.core.repository.EquipementRepository;
import com.astalange.core.repository.CategorieRepository;
import org.springframework.ui.Model;
import org.springframework.data.jpa.domain.Specification;
import jakarta.persistence.criteria.Predicate;
import java.util.ArrayList;

@Controller
public class DotationController {

    private final DotationRepository dotationRepository;
    private final DotationService dotationService;
    private final SaisonRepository saisonRepository;
    private final EquipementRepository equipementRepository;
    private final CategorieRepository categorieRepository;

    public DotationController(DotationRepository dotationRepository, DotationService dotationService, SaisonRepository saisonRepository, EquipementRepository equipementRepository, CategorieRepository categorieRepository) {
        this.dotationRepository = dotationRepository;
        this.dotationService = dotationService;
        this.saisonRepository = saisonRepository;
        this.equipementRepository = equipementRepository;
        this.categorieRepository = categorieRepository;
    }

    private Specification<Dotation> buildSpecification(Long equipementId, Long categorieId, Boolean fourni, Saison saisonActive) {
        return (root, query, cb) -> {
            if (Long.class != query.getResultType() && long.class != query.getResultType()) {
                root.fetch("equipement", jakarta.persistence.criteria.JoinType.LEFT);
                jakarta.persistence.criteria.Fetch<Object, Object> licenceFetch = root.fetch("licence", jakarta.persistence.criteria.JoinType.LEFT);
                licenceFetch.fetch("adherent", jakarta.persistence.criteria.JoinType.LEFT);
                licenceFetch.fetch("categorie", jakarta.persistence.criteria.JoinType.LEFT);
            }

            List<Predicate> predicates = new ArrayList<>();
            if (saisonActive != null) {
                predicates.add(cb.equal(root.get("licence").get("saison"), saisonActive));
            }
            if (equipementId != null) {
                predicates.add(cb.equal(root.get("equipement").get("id"), equipementId));
            }
            if (categorieId != null) {
                predicates.add(cb.equal(root.get("licence").get("categorie").get("id"), categorieId));
            }
            if (fourni != null) {
                predicates.add(cb.equal(root.get("fourni"), fourni));
            }
            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }

    @GetMapping("/admin/equipements/recherche")
    public String rechercheEquipements(
            @RequestParam(required = false) Long equipementId,
            @RequestParam(required = false) Long categorieId,
            @RequestParam(required = false) Boolean fourni,
            Model model) {

        Saison saisonActive = saisonRepository.findByEstActiveTrue().orElse(null);
        Specification<Dotation> spec = buildSpecification(equipementId, categorieId, fourni, saisonActive);
        List<Dotation> dotations = dotationRepository.findAll(spec);

        model.addAttribute("dotations", dotations);
        model.addAttribute("equipements", equipementRepository.findAll());
        model.addAttribute("categories", categorieRepository.findAll());
        model.addAttribute("equipementId", equipementId);
        model.addAttribute("categorieId", categorieId);
        model.addAttribute("fourni", fourni);

        return "parametrage/equipements_recherche";
    }

    @GetMapping("/admin/equipements/recherche/export")
    public ResponseEntity<byte[]> exportRechercheEquipements(
            @RequestParam(required = false) Long equipementId,
            @RequestParam(required = false) Long categorieId,
            @RequestParam(required = false) Boolean fourni) {

        Saison saisonActive = saisonRepository.findByEstActiveTrue().orElse(null);
        Specification<Dotation> spec = buildSpecification(equipementId, categorieId, fourni, saisonActive);
        List<Dotation> dotations = dotationRepository.findAll(spec);

        String csvContent = dotationService.genererCsvSearchEquipement(dotations);
        byte[] csvBytes = csvContent.getBytes(java.nio.charset.StandardCharsets.UTF_8);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment", "recherche_equipements_" + LocalDate.now() + ".csv");
        headers.setContentType(MediaType.parseMediaType("text/csv; charset=UTF-8"));

        return new ResponseEntity<>(csvBytes, headers, org.springframework.http.HttpStatus.OK);
    }

    @GetMapping("/admin/equipements/export-commande")
    public ResponseEntity<byte[]> exportCommande() {
        Saison saisonActive = saisonRepository.findByEstActiveTrue()
                .orElseThrow(() -> new IllegalStateException("Aucune saison active"));
        
        String csvContent = dotationService.genererCsvCommandeEquipement(saisonActive);
        byte[] csvBytes = csvContent.getBytes(java.nio.charset.StandardCharsets.UTF_8);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment", "commande_equipements_" + LocalDate.now() + ".csv");
        headers.setContentType(MediaType.parseMediaType("text/csv; charset=UTF-8"));

        return new ResponseEntity<>(csvBytes, headers, org.springframework.http.HttpStatus.OK);
    }

    @PostMapping("/dotations/{id}")
    public String updateDotation(
            @PathVariable Long id,
            @RequestParam Long adherentId,
            @RequestParam(required = false, defaultValue = "") String taille,
            @RequestParam(required = false, defaultValue = "") String flocage,
            @RequestParam(required = false, defaultValue = "") String numero,
            @RequestParam(required = false) Boolean fourni,
            @RequestParam(required = false) Boolean choisi) {

        Dotation dotation = dotationRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Invalid Dotation ID: " + id));

        dotation.setTaille(taille);
        dotation.setFlocage(flocage);
        dotation.setNumero(numero);
        dotation.setFourni(fourni != null && fourni);
        
        if (dotation.getLicence().getCategorie().isEquipementObligatoire(dotation.getEquipement().getId())) {
            dotation.setChoisi(true);
        } else {
            dotation.setChoisi(choisi != null && choisi);
        }

        dotationRepository.save(dotation);

        return "redirect:/adherents/" + adherentId + "/edit";
    }

    @Transactional
    @PostMapping("/dotations/bulk")
    public String bulkUpdateDotations(
            @RequestParam Long adherentId,
            @RequestParam("dotationIds") List<Long> dotationIds,
            HttpServletRequest request) {

        for (Long id : dotationIds) {
            Dotation dotation = dotationRepository.findById(id)
                    .orElseThrow(() -> new IllegalArgumentException("Invalid Dotation ID: " + id));

            String taille = request.getParameter("taille_" + id);
            String numero = request.getParameter("numero_" + id);
            String flocage = request.getParameter("flocage_" + id);
            String choisiParam = request.getParameter("choisi_" + id);
            String fourniParam = request.getParameter("fourni_" + id);

            if (taille != null) dotation.setTaille(taille);
            if (numero != null) dotation.setNumero(numero);
            if (flocage != null) dotation.setFlocage(flocage);

            if (dotation.getLicence().getCategorie().isEquipementObligatoire(dotation.getEquipement().getId())) {
                dotation.setChoisi(true);
            } else {
                dotation.setChoisi(choisiParam != null);
            }

            dotation.setFourni(fourniParam != null);

            dotationRepository.save(dotation);
        }

        return "redirect:/adherents/" + adherentId + "/edit";
    }
}
