package com.astalange.web.controller;

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

import java.util.List;

@Controller
@Transactional
public class LicenceController {

    private final AdherentRepository adherentRepository;
    private final CategorieRepository categorieRepository;
    private final LicenceRepository licenceRepository;
    private final EquipementRepository equipementRepository;
    private final DotationRepository dotationRepository;
    private final SaisonRepository saisonRepository;
    private final EquipeRepository equipeRepository;
    private final com.astalange.core.service.CategorieService categorieService;

    public LicenceController(AdherentRepository adherentRepository, 
                             CategorieRepository categorieRepository, 
                             LicenceRepository licenceRepository,
                             EquipementRepository equipementRepository,
                             DotationRepository dotationRepository,
                             SaisonRepository saisonRepository,
                             EquipeRepository equipeRepository,
                             com.astalange.core.service.CategorieService categorieService) {
        this.adherentRepository = adherentRepository;
        this.categorieRepository = categorieRepository;
        this.licenceRepository = licenceRepository;
        this.equipementRepository = equipementRepository;
        this.dotationRepository = dotationRepository;
        this.saisonRepository = saisonRepository;
        this.equipeRepository = equipeRepository;
        this.categorieService = categorieService;
    }

    @PostMapping("/adherents/{id}/licences")
    public String addLicence(
            @PathVariable Long id,
            @RequestParam Long categorieId,
            @RequestParam String etat,
            @RequestParam(required = false) String numeroLicence,
            @RequestParam(required = false) String typeDemande,
            @RequestParam(required = false) String typeLicence,
            @RequestParam(required = false) Long equipeId) {

        Adherent adherent = adherentRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Invalid Adherent ID"));
        
        List<Licence> existingLicences = licenceRepository.findByAdherentId(id);
        if (!existingLicences.isEmpty()) {
            return "redirect:/adherents/" + id + "/edit";
        }

        Categorie categorie = categorieRepository.findById(categorieId)
                .orElseThrow(() -> new IllegalArgumentException("Invalid Categorie ID"));
                
        Saison saisonActive = saisonRepository.findByEstActiveTrue()
                .orElseThrow(() -> new IllegalStateException("Aucune saison active trouvée"));

        Licence licence = new Licence();
        licence.setAdherent(adherent);
        licence.setCategorie(categorie);
        licence.setSaison(saisonActive);
        licence.setEtat(etat);
        licence.setNumeroLicence(numeroLicence);
        licence.setTypeDemande(typeDemande);
        licence.setTypeLicence(typeLicence);

        if (equipeId != null) {
            Equipe equipe = equipeRepository.findById(equipeId)
                    .orElseThrow(() -> new IllegalArgumentException("Invalid Equipe ID"));
            licence.setEquipe(equipe);
        }

        licence = licenceRepository.save(licence);

        // Auto-initialize dotations for all configured equipments of the category
        List<CategorieEquipement> catEquipements = categorie.getCategorieEquipements();
        if (catEquipements != null) {
            for (CategorieEquipement ce : catEquipements) {
                Dotation dotation = new Dotation();
                dotation.setLicence(licence);
                dotation.setEquipement(ce.getEquipement());
                dotation.setTaille("");
                dotation.setFlocage(adherent.getNom().toUpperCase() + " " + adherent.getPrenom());
                dotation.setNumero("");
                dotation.setFourni(false);
                dotation.setChoisi(Boolean.TRUE.equals(ce.getObligatoire()));
                dotationRepository.save(dotation);
            }
        }

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

    @PostMapping("/adherents/{adherentId}/licences/{licenceId}/update")
    public String updateLicence(
            @PathVariable Long adherentId,
            @PathVariable Long licenceId,
            @RequestParam Long categorieId,
            @RequestParam String etat,
            @RequestParam(required = false) String numeroLicence,
            @RequestParam(required = false) String typeDemande,
            @RequestParam(required = false) String typeLicence,
            @RequestParam(required = false) Long equipeId) {

        Licence licence = licenceRepository.findById(licenceId)
                .orElseThrow(() -> new IllegalArgumentException("Invalid Licence ID"));

        Categorie categorie = categorieRepository.findById(categorieId)
                .orElseThrow(() -> new IllegalArgumentException("Invalid Categorie ID"));

        licence.setCategorie(categorie);
        licence.setEtat(etat);
        licence.setNumeroLicence(numeroLicence);
        licence.setTypeDemande(typeDemande);
        licence.setTypeLicence(typeLicence);

        if (equipeId != null) {
            Equipe equipe = equipeRepository.findById(equipeId)
                    .orElseThrow(() -> new IllegalArgumentException("Invalid Equipe ID"));
            licence.setEquipe(equipe);
        } else {
            licence.setEquipe(null);
        }

        licence = licenceRepository.save(licence);
        
        // Sync dotations when category changes
        categorieService.syncDotationsForLicence(licence);

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

    @org.springframework.web.bind.annotation.GetMapping("/admin/licences/recherche")
    public String rechercheLicences(
            @RequestParam(required = false) String nom,
            @RequestParam(required = false) String prenom,
            @RequestParam(required = false) Long categorieId,
            @RequestParam(required = false) String numeroLicence,
            @RequestParam(required = false) String email,
            @RequestParam(required = false) String typeDemande,
            org.springframework.ui.Model model) {

        Saison saisonActive = saisonRepository.findByEstActiveTrue().orElse(null);
        org.springframework.data.jpa.domain.Specification<Licence> spec = buildLicenceSpecification(nom, prenom, categorieId, numeroLicence, email, typeDemande, saisonActive);
        
        List<Licence> licences = licenceRepository.findAll(spec);

        model.addAttribute("licences", licences);
        model.addAttribute("categories", categorieRepository.findAll());
        model.addAttribute("nomFilter", nom);
        model.addAttribute("prenomFilter", prenom);
        model.addAttribute("categorieId", categorieId);
        model.addAttribute("numeroLicenceFilter", numeroLicence);
        model.addAttribute("emailFilter", email);
        model.addAttribute("typeDemandeFilter", typeDemande);

        return "parametrage/licences_recherche";
    }

    @org.springframework.web.bind.annotation.GetMapping("/admin/licences/recherche/export")
    public org.springframework.http.ResponseEntity<byte[]> exportRechercheLicences(
            @RequestParam(required = false) String nom,
            @RequestParam(required = false) String prenom,
            @RequestParam(required = false) Long categorieId,
            @RequestParam(required = false) String numeroLicence,
            @RequestParam(required = false) String email,
            @RequestParam(required = false) String typeDemande) {

        Saison saisonActive = saisonRepository.findByEstActiveTrue().orElse(null);
        org.springframework.data.jpa.domain.Specification<Licence> spec = buildLicenceSpecification(nom, prenom, categorieId, numeroLicence, email, typeDemande, saisonActive);
        List<Licence> licences = licenceRepository.findAll(spec);

        StringBuilder sb = new StringBuilder();
        sb.append('\ufeff');
        sb.append("Nom;Prénom;Catégorie;N° Licence;Email;Type de Demande;Saison;Etat\n");

        for (Licence l : licences) {
            String n = l.getAdherent() != null && l.getAdherent().getNom() != null ? l.getAdherent().getNom() : "";
            String p = l.getAdherent() != null && l.getAdherent().getPrenom() != null ? l.getAdherent().getPrenom() : "";
            String c = l.getCategorie() != null ? l.getCategorie().getNom() : "";
            String num = l.getNumeroLicence() != null ? l.getNumeroLicence() : "";
            String e = l.getAdherent() != null && l.getAdherent().getEmail() != null ? l.getAdherent().getEmail() : "";
            String td = l.getTypeDemande() != null ? l.getTypeDemande() : "";
            String s = l.getSaison() != null ? l.getSaison().getNom() : "";
            String etat = l.getEtat() != null ? l.getEtat() : "";

            sb.append(escapeCsv(n)).append(";")
              .append(escapeCsv(p)).append(";")
              .append(escapeCsv(c)).append(";")
              .append(escapeCsv(num)).append(";")
              .append(escapeCsv(e)).append(";")
              .append(escapeCsv(td)).append(";")
              .append(escapeCsv(s)).append(";")
              .append(escapeCsv(etat)).append("\n");
        }

        byte[] csvBytes = sb.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
        org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();
        headers.setContentDispositionFormData("attachment", "recherche_licences_" + java.time.LocalDate.now() + ".csv");
        headers.setContentType(org.springframework.http.MediaType.parseMediaType("text/csv; charset=UTF-8"));

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

    private String escapeCsv(String value) {
        if (value == null) return "";
        if (value.contains("\"")) value = value.replace("\"", "\"\"");
        if (value.contains(";") || value.contains("\n") || value.contains("\"")) return "\"" + value + "\"";
        return value;
    }

    private org.springframework.data.jpa.domain.Specification<Licence> buildLicenceSpecification(
            String nom, String prenom, Long categorieId, String numeroLicence, String email, String typeDemande, Saison saisonActive) {
        return (root, query, cb) -> {
            List<jakarta.persistence.criteria.Predicate> predicates = new java.util.ArrayList<>();
            
            if (Long.class != query.getResultType() && long.class != query.getResultType()) {
                root.fetch("adherent", jakarta.persistence.criteria.JoinType.LEFT);
                root.fetch("categorie", jakarta.persistence.criteria.JoinType.LEFT);
            }

            if (saisonActive != null) {
                predicates.add(cb.equal(root.get("saison"), saisonActive));
            }
            if (nom != null && !nom.trim().isEmpty()) {
                predicates.add(cb.like(cb.lower(root.get("adherent").get("nom")), "%" + nom.trim().toLowerCase() + "%"));
            }
            if (prenom != null && !prenom.trim().isEmpty()) {
                predicates.add(cb.like(cb.lower(root.get("adherent").get("prenom")), "%" + prenom.trim().toLowerCase() + "%"));
            }
            if (categorieId != null) {
                predicates.add(cb.equal(root.get("categorie").get("id"), categorieId));
            }
            if (numeroLicence != null && !numeroLicence.trim().isEmpty()) {
                predicates.add(cb.like(cb.lower(root.get("numeroLicence")), "%" + numeroLicence.trim().toLowerCase() + "%"));
            }
            if (email != null && !email.trim().isEmpty()) {
                predicates.add(cb.like(cb.lower(root.get("adherent").get("email")), "%" + email.trim().toLowerCase() + "%"));
            }
            if (typeDemande != null && !typeDemande.trim().isEmpty()) {
                predicates.add(cb.equal(root.get("typeDemande"), typeDemande.trim()));
            }
            return cb.and(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]));
        };
    }
}
