package dev.lions.btpxpress.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;

/**
 * Service pour récupérer et transformer les données du dashboard depuis l'API backend.
 * 
 * <p>Ce service encapsule tous les appels à l'API dashboard et transforme
 * les réponses JSON en objets Java utilisables par les vues JSF.</p>
 * 
 * @author BTP Xpress Team
 * @version 1.0
 */
@ApplicationScoped
public class DashboardService {

    private static final Logger logger = LoggerFactory.getLogger(DashboardService.class);

    @Inject
    @RestClient
    BtpXpressApiClient apiClient;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * Récupère les métriques du dashboard principal.
     * 
     * @return JsonNode contenant les métriques ou null en cas d'erreur
     */
    public JsonNode getDashboardPrincipal() {
        try {
            Response response = apiClient.getDashboardPrincipal();
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                Object entity = response.getEntity();
                if (entity == null) {
                    logger.warn("Réponse vide du dashboard principal");
                    return null;
                }
                // REST Client avec Jackson désérialise déjà en Map/Object
                return convertToJsonNode(entity);
            } else {
                logger.error("Erreur API dashboard principal: status {}", response.getStatus());
                return null;
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération du dashboard principal", e);
            return null;
        }
    }

    /**
     * Convertit un objet en JsonNode, quel que soit son type (String, Map, Object, etc.).
     */
    private JsonNode convertToJsonNode(Object entity) {
        try {
            if (entity instanceof String) {
                return objectMapper.readTree((String) entity);
            } else if (entity instanceof Map || entity instanceof List) {
                // Map ou List sont déjà désérialisés par REST Client
                return objectMapper.valueToTree(entity);
            } else {
                // Pour les autres objets, conversion via ObjectMapper
                return objectMapper.valueToTree(entity);
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la conversion en JsonNode", e);
            return null;
        }
    }

    /**
     * Récupère les métriques des chantiers.
     * 
     * @return JsonNode contenant les métriques des chantiers ou null en cas d'erreur
     */
    public JsonNode getDashboardChantiers() {
        try {
            Response response = apiClient.getDashboardChantiers();
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                Object entity = response.getEntity();
                return convertToJsonNode(entity);
            } else {
                logger.error("Erreur API dashboard chantiers: status {}", response.getStatus());
                return null;
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération du dashboard chantiers", e);
            return null;
        }
    }

    /**
     * Récupère les métriques financières.
     * 
     * @param periode Période en jours (défaut: 30)
     * @return JsonNode contenant les métriques financières ou null en cas d'erreur
     */
    public JsonNode getDashboardFinances(int periode) {
        try {
            Response response = apiClient.getDashboardFinances(periode);
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                Object entity = response.getEntity();
                return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
            } else {
                logger.error("Erreur API dashboard finances: status {}", response.getStatus());
                return null;
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération du dashboard finances", e);
            return null;
        }
    }

    /**
     * Récupère les métriques de maintenance.
     * 
     * @return JsonNode contenant les métriques de maintenance ou null en cas d'erreur
     */
    public JsonNode getDashboardMaintenance() {
        try {
            Response response = apiClient.getDashboardMaintenance();
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                Object entity = response.getEntity();
                return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
            } else {
                logger.error("Erreur API dashboard maintenance: status {}", response.getStatus());
                return null;
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération du dashboard maintenance", e);
            return null;
        }
    }

    /**
     * Récupère les métriques des ressources.
     * 
     * @return JsonNode contenant les métriques des ressources ou null en cas d'erreur
     */
    public JsonNode getDashboardRessources() {
        try {
            Response response = apiClient.getDashboardRessources();
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                Object entity = response.getEntity();
                return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
            } else {
                logger.error("Erreur API dashboard ressources: status {}", response.getStatus());
                return null;
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération du dashboard ressources", e);
            return null;
        }
    }

    /**
     * Récupère les alertes.
     * 
     * @return JsonNode contenant les alertes ou null en cas d'erreur
     */
    public JsonNode getAlertes() {
        try {
            Response response = apiClient.getAlertes();
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                Object entity = response.getEntity();
                return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
            } else {
                logger.error("Erreur API alertes: status {}", response.getStatus());
                return null;
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération des alertes", e);
            return null;
        }
    }

    /**
     * Récupère les KPIs.
     * 
     * @param periode Période en jours (défaut: 30)
     * @return JsonNode contenant les KPIs ou null en cas d'erreur
     */
    public JsonNode getKPI(int periode) {
        try {
            Response response = apiClient.getKPI(periode);
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                Object entity = response.getEntity();
                return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
            } else {
                logger.error("Erreur API KPI: status {}", response.getStatus());
                return null;
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération des KPIs", e);
            return null;
        }
    }

    /**
     * Récupère les activités récentes.
     * 
     * @param limit Nombre d'activités à récupérer
     * @return JsonNode contenant les activités récentes ou null en cas d'erreur
     */
    public JsonNode getActivitesRecentes(int limit) {
        try {
            Response response = apiClient.getActivitesRecentes(limit);
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                Object entity = response.getEntity();
                return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
            } else {
                logger.error("Erreur API activités récentes: status {}", response.getStatus());
                return null;
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération des activités récentes", e);
            return null;
        }
    }

    /**
     * Récupère le résumé quotidien.
     * 
     * @return JsonNode contenant le résumé quotidien ou null en cas d'erreur
     */
    public JsonNode getResumeQuotidien() {
        try {
            Response response = apiClient.getResumeQuotidien();
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                Object entity = response.getEntity();
                return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
            } else {
                logger.error("Erreur API résumé quotidien: status {}", response.getStatus());
                return null;
            }
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération du résumé quotidien", e);
            return null;
        }
    }

    /**
     * Récupère le nombre de clients.
     * 
     * @return Nombre de clients ou 0 en cas d'erreur
     */
    public int getNombreClients() {
        try {
            Response response = apiClient.getClients();
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                List<?> clients = (List<?>) response.getEntity();
                return clients != null ? clients.size() : 0;
            }
            return 0;
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération du nombre de clients", e);
            return 0;
        }
    }

    /**
     * Récupère le nombre de devis en attente.
     * Filtre côté client les devis avec statut EN_ATTENTE.
     * 
     * @return Nombre de devis en attente ou 0 en cas d'erreur
     */
    @SuppressWarnings("unchecked")
    public int getNombreDevisEnAttente() {
        try {
            Response response = apiClient.getDevis();
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                List<Map<String, Object>> devis = response.readEntity(List.class);
                if (devis == null) {
                    return 0;
                }
                // Filtrer par statut EN_ATTENTE côté client
                long count = devis.stream()
                    .filter(d -> {
                        Object statut = d.get("statut");
                        return statut != null && 
                               (statut.toString().equalsIgnoreCase("EN_ATTENTE") || 
                                statut.toString().equalsIgnoreCase("EN ATTENTE"));
                    })
                    .count();
                return (int) count;
            }
            return 0;
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération du nombre de devis", e);
            return 0;
        }
    }

    /**
     * Récupère le nombre de factures impayées.
     * Filtre côté client les factures avec statut IMPAYEE ou EN_RETARD.
     * 
     * @return Nombre de factures impayées ou 0 en cas d'erreur
     */
    @SuppressWarnings("unchecked")
    public int getNombreFacturesImpayees() {
        try {
            Response response = apiClient.getFactures();
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                List<Map<String, Object>> factures = response.readEntity(List.class);
                if (factures == null) {
                    return 0;
                }
                // Filtrer par statut IMPAYEE ou EN_RETARD côté client
                long count = factures.stream()
                    .filter(f -> {
                        Object statut = f.get("statut");
                        if (statut == null) {
                            return false;
                        }
                        String statutStr = statut.toString().toUpperCase();
                        return statutStr.equals("IMPAYEE") || 
                               statutStr.equals("EN_RETARD") ||
                               statutStr.equals("EN RETARD");
                    })
                    .count();
                return (int) count;
            }
            return 0;
        } catch (Exception e) {
            logger.error("Erreur lors de la récupération du nombre de factures", e);
            return 0;
        }
    }
}

