package dev.lions.btpxpress.view;

import dev.lions.btpxpress.service.FactureService;
import jakarta.annotation.PostConstruct;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

@Named("factureView")
@ViewScoped
@Getter
@Setter
public class FactureView extends BaseListView<FactureView.Facture, Long> {

    private static final Logger LOG = LoggerFactory.getLogger(FactureView.class);

    @Inject
    FactureService factureService;

    private String filtreNumero;
    private String filtreClient;
    private String filtreStatut;
    private Long factureId;

    @PostConstruct
    public void init() {
        if (filtreStatut == null) {
            filtreStatut = "TOUS";
        }
        loadItems();
    }

    /**
     * Définit le filtre de statut (utilisé depuis les pages filtrées).
     */
    public void setFiltreStatut(String statut) {
        this.filtreStatut = statut;
    }

    @Override
    public void loadItems() {
        loading = true;
        try {
            items = new ArrayList<>();

            // Récupération depuis l'API backend
            List<Map<String, Object>> facturesData = factureService.getAllFactures();

            for (Map<String, Object> data : facturesData) {
                Facture f = new Facture();

                // Mapping des données de l'API vers l'objet Facture
                f.setId(data.get("id") != null ? Long.valueOf(data.get("id").toString().hashCode()) : null);
                f.setNumero((String) data.get("numero"));
                f.setObjet((String) data.get("objet"));

                // Le client peut être un objet ou une chaîne
                Object clientObj = data.get("client");
                if (clientObj instanceof Map) {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> clientData = (Map<String, Object>) clientObj;
                    String entreprise = (String) clientData.get("entreprise");
                    String nom = (String) clientData.get("nom");
                    String prenom = (String) clientData.get("prenom");
                    f.setClient(entreprise != null && !entreprise.trim().isEmpty() ?
                        entreprise : (prenom != null ? prenom + " " : "") + (nom != null ? nom : ""));
                } else if (clientObj instanceof String) {
                    f.setClient((String) clientObj);
                } else {
                    f.setClient("N/A");
                }

                // Conversion des dates
                if (data.get("dateEmission") != null) {
                    f.setDateEmission(LocalDate.parse(data.get("dateEmission").toString()));
                }
                if (data.get("dateEcheance") != null) {
                    f.setDateEcheance(LocalDate.parse(data.get("dateEcheance").toString()));
                }
                if (data.get("datePaiement") != null) {
                    f.setDatePaiement(LocalDate.parse(data.get("datePaiement").toString()));
                }

                f.setStatut((String) data.get("statut"));

                // Montants
                Object montantHTObj = data.get("montantHT");
                if (montantHTObj != null) {
                    f.setMontantHT(montantHTObj instanceof Number ?
                        ((Number) montantHTObj).doubleValue() :
                        Double.parseDouble(montantHTObj.toString()));
                } else {
                    f.setMontantHT(0.0);
                }

                Object montantTTCObj = data.get("montantTTC");
                if (montantTTCObj != null) {
                    f.setMontantTTC(montantTTCObj instanceof Number ?
                        ((Number) montantTTCObj).doubleValue() :
                        Double.parseDouble(montantTTCObj.toString()));
                } else {
                    f.setMontantTTC(0.0);
                }

                Object montantPayeObj = data.get("montantPaye");
                if (montantPayeObj != null) {
                    f.setMontantPaye(montantPayeObj instanceof Number ?
                        ((Number) montantPayeObj).doubleValue() :
                        Double.parseDouble(montantPayeObj.toString()));
                } else {
                    f.setMontantPaye(0.0);
                }

                if (data.get("dateCreation") != null) {
                    f.setDateCreation(LocalDateTime.parse(data.get("dateCreation").toString()));
                }

                items.add(f);
            }

            LOG.info("Factures chargées depuis l'API : {} élément(s)", items.size());
            applyFilters(items, buildFilters());
        } catch (Exception e) {
            LOG.error("Erreur chargement factures depuis l'API", e);
            // En cas d'erreur, on garde une liste vide
            items = new ArrayList<>();
        } finally {
            loading = false;
        }
    }

    private List<Predicate<Facture>> buildFilters() {
        List<Predicate<Facture>> filters = new ArrayList<>();
        if (filtreNumero != null && !filtreNumero.trim().isEmpty()) {
            filters.add(f -> f.getNumero().toLowerCase().contains(filtreNumero.toLowerCase()));
        }
        if (filtreClient != null && !filtreClient.trim().isEmpty()) {
            filters.add(f -> f.getClient().toLowerCase().contains(filtreClient.toLowerCase()));
        }
        if (filtreStatut != null && !filtreStatut.trim().isEmpty() && !"TOUS".equals(filtreStatut)) {
            filters.add(f -> f.getStatut().equals(filtreStatut));
        }
        return filters;
    }

    @Override
    protected void resetFilterFields() {
        filtreNumero = null;
        filtreClient = null;
        filtreStatut = "TOUS";
    }

    @Override
    protected String getDetailsPath() {
        return "/factures/";
    }

    @Override
    protected String getCreatePath() {
        return "/factures/nouveau";
    }

    @Override
    protected void performDelete() {
        LOG.info("Suppression facture : {}", selectedItem.getId());
    }

    @Override
    protected Facture createNewEntity() {
        Facture facture = new Facture();
        facture.setStatut("BROUILLON");
        facture.setDateEmission(LocalDate.now());
        facture.setDateEcheance(LocalDate.now().plusDays(30));
        facture.setMontantHT(0.0);
        facture.setMontantTTC(0.0);
        facture.setMontantPaye(0.0);
        facture.setDateCreation(LocalDateTime.now());
        return facture;
    }

    @Override
    protected void performCreate() {
        if (selectedItem.getId() == null) {
            selectedItem.setId(System.currentTimeMillis());
        }
        selectedItem.setDateCreation(LocalDateTime.now());
        items.add(selectedItem);
        LOG.info("Created: {}", selectedItem);
    }

    @Override
    protected void performUpdate() {
        LOG.info("Updated: {}", selectedItem);
    }

    @Override
    protected Long getEntityId(Facture entity) {
        return entity.getId();
    }

    /**
     * Initialise une nouvelle facture pour la création.
     */
    @Override
    public String createNew() {
        selectedItem = new Facture();
        selectedItem.setStatut("BROUILLON");
        selectedItem.setDateEmission(LocalDate.now());
        selectedItem.setDateEcheance(LocalDate.now().plusDays(30));
        return getCreatePath() + "?faces-redirect=true";
    }

    /**
     * Sauvegarde une nouvelle facture.
     */
    public String saveNew() {
        if (selectedItem == null) {
            selectedItem = new Facture();
        }
        selectedItem.setId(System.currentTimeMillis()); // Simulation ID
        selectedItem.setDateCreation(LocalDateTime.now());
        items.add(selectedItem);
        LOG.info("Nouvelle facture créée : {}", selectedItem.getNumero());
        return "/factures?faces-redirect=true";
    }

    /**
     * Charge une facture par son ID depuis les paramètres de la requête.
     */
    public void loadFactureById() {
        if (factureId != null) {
            loadItems(); // S'assurer que les items sont chargés
            selectedItem = items.stream()
                    .filter(f -> f.getId().equals(factureId))
                    .findFirst()
                    .orElse(null);
            if (selectedItem == null) {
                LOG.warn("Facture avec ID {} non trouvé", factureId);
            }
        }
    }

    /**
     * Affiche les détails d'une facture.
     */
    public String viewDetails(Long id) {
        selectedItem = items.stream()
                .filter(f -> f.getId().equals(id))
                .findFirst()
                .orElse(null);
        if (selectedItem != null) {
            return getDetailsPath() + "details?id=" + id + "&faces-redirect=true";
        }
        return "/factures?faces-redirect=true";
    }

    /**
     * Calcule le montant restant à payer.
     */
    public double getMontantRestant(Facture facture) {
        return facture.getMontantTTC() - facture.getMontantPaye();
    }

    /**
     * Vérifie si une facture est en retard.
     */
    public boolean isEnRetard(Facture facture) {
        return facture.getDateEcheance() != null &&
               facture.getDateEcheance().isBefore(LocalDate.now()) &&
               !"PAYEE".equals(facture.getStatut());
    }

    @lombok.Getter
    @lombok.Setter
    public static class Facture {
        private Long id;
        private String numero;
        private String objet;
        private String client;
        private LocalDate dateEmission;
        private LocalDate dateEcheance;
        private LocalDate datePaiement;
        private String statut;
        private double montantHT;
        private double montantTTC;
        private double montantPaye;
        private LocalDateTime dateCreation;
    }
}
