package dev.lions.user.manager.client.view;

import dev.lions.user.manager.client.service.AuditServiceClient;
import dev.lions.user.manager.client.service.RealmServiceClient;
import dev.lions.user.manager.dto.audit.AuditLogDTO;
import dev.lions.user.manager.dto.common.CountDTO;
import dev.lions.user.manager.enums.audit.TypeActionAudit;
import jakarta.annotation.PostConstruct;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import lombok.Data;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import java.io.OutputStream;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

@Named("auditConsultationBean")
@ViewScoped
@Data
public class AuditConsultationBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger LOGGER = Logger.getLogger(AuditConsultationBean.class.getName());
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");

    @Inject
    @RestClient
    private AuditServiceClient auditServiceClient;

    @Inject
    @RestClient
    private RealmServiceClient realmServiceClient;

    private List<AuditLogDTO> auditLogs = new ArrayList<>();
    private AuditLogDTO selectedLog;

    private String acteurUsername;
    private LocalDateTime dateDebut;
    private LocalDateTime dateFin;
    private TypeActionAudit selectedTypeAction;
    private String ressourceType;
    private Boolean succes;

    private int currentPage = 0;
    private int pageSize = 50;
    private long totalRecords = 0;

    private Map<TypeActionAudit, Long> actionStatistics;
    private Map<String, Long> userActivityStatistics;
    private long failureCount = 0;
    private long successCount = 0;

    private List<TypeActionAudit> typeActionOptions = List.of(TypeActionAudit.values());
    private List<String> availableRealms = new ArrayList<>();

    @PostConstruct
    public void init() {
        loadRealms();
        loadStatistics();
        loadRecentLogs();
    }

    public void searchLogs() {
        try {
            String dateDebutStr = toIsoString(dateDebut);
            String dateFinStr = toIsoString(dateFin);

            auditLogs = auditServiceClient.searchLogs(
                    acteurUsername,
                    dateDebutStr,
                    dateFinStr,
                    selectedTypeAction,
                    ressourceType,
                    succes,
                    currentPage,
                    pageSize);

            if (auditLogs == null) auditLogs = new ArrayList<>();
            totalRecords = auditLogs.size();
            addSuccessMessage("Recherche effectuée : " + totalRecords + " résultat(s)");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la recherche: " + e.getMessage());
            addErrorMessage("Erreur lors de la recherche : " + e.getMessage());
        }
    }

    public void loadRecentLogs() {
        try {
            auditLogs = auditServiceClient.searchLogs(
                    null, null, null, null, null, null, 0, pageSize);
            if (auditLogs == null) auditLogs = new ArrayList<>();
            totalRecords = successCount + failureCount;
            if (totalRecords == 0) {
                totalRecords = auditLogs.size();
            }
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement initial des logs: " + e.getMessage());
            auditLogs = new ArrayList<>();
        }
    }

    public void loadStatistics() {
        try {
            String dateDebutStr = toIsoString(dateDebut);
            String dateFinStr = toIsoString(dateFin);

            CountDTO failures = auditServiceClient.getFailureCount(dateDebutStr, dateFinStr);
            failureCount = failures != null ? failures.getCount() : 0;

            CountDTO successes = auditServiceClient.getSuccessCount(dateDebutStr, dateFinStr);
            successCount = successes != null ? successes.getCount() : 0;

            totalRecords = successCount + failureCount;
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des statistiques: " + e.getMessage());
        }
        try {
            String dateDebutStr = toIsoString(dateDebut);
            String dateFinStr = toIsoString(dateFin);
            actionStatistics = auditServiceClient.getActionStatistics(dateDebutStr, dateFinStr);
            userActivityStatistics = auditServiceClient.getUserActivityStatistics(dateDebutStr, dateFinStr);
        } catch (Exception e) {
            LOGGER.warning("Statistiques détaillées non disponibles: " + e.getMessage());
        }
    }

    public void exportToCSV() {
        try {
            String dateDebutStr = toIsoString(dateDebut);
            String dateFinStr = toIsoString(dateFin);

            try (jakarta.ws.rs.core.Response response = auditServiceClient.exportLogsToCSV(dateDebutStr, dateFinStr)) {
                String csv = response.readEntity(String.class);

                FacesContext facesContext = FacesContext.getCurrentInstance();
                ExternalContext externalContext = facesContext.getExternalContext();

                String disposition = response.getHeaderString("Content-Disposition");
                String fileName = "audit-logs.csv";
                if (disposition != null && disposition.contains("filename=")) {
                    fileName = disposition.substring(disposition.indexOf("filename=") + 9).replace("\"", "");
                }

                byte[] contentBytes = csv.getBytes(java.nio.charset.StandardCharsets.UTF_8);

                externalContext.setResponseContentType("text/csv; charset=UTF-8");
                externalContext.setResponseContentLength(contentBytes.length);
                externalContext.setResponseHeader("Content-Disposition",
                        "attachment; filename=\"" + fileName + "\"");

                try (OutputStream out = externalContext.getResponseOutputStream()) {
                    out.write(contentBytes);
                    out.flush();
                }

                facesContext.responseComplete();
            }
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'export: " + e.getMessage());
            addErrorMessage("Erreur lors de l'export : " + e.getMessage());
        }
    }

    public void resetFilters() {
        acteurUsername = null;
        dateDebut = null;
        dateFin = null;
        selectedTypeAction = null;
        ressourceType = null;
        succes = null;
        currentPage = 0;
        loadStatistics();
        loadRecentLogs();
    }

    public void previousPage() {
        if (currentPage > 0) {
            currentPage--;
            searchLogs();
        }
    }

    public void nextPage() {
        currentPage++;
        searchLogs();
    }

    public long getSuccessRate() {
        if (totalRecords == 0) return 0;
        return (successCount * 100) / totalRecords;
    }

    private void loadRealms() {
        try {
            List<String> realms = realmServiceClient.getAllRealms();
            availableRealms = (realms != null && !realms.isEmpty()) ? new ArrayList<>(realms) : new ArrayList<>();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des realms: " + e.getMessage());
            availableRealms = new ArrayList<>();
        }
    }

    public void loadLogsByActeur(String acteur) {
        try {
            List<AuditLogDTO> result = auditServiceClient.getLogsByActor(acteur, 100);
            auditLogs = result != null ? result : new ArrayList<>();
            totalRecords = auditLogs.size();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des logs par acteur: " + e.getMessage());
            addErrorMessage("Erreur lors du chargement : " + e.getMessage());
        }
    }

    public void loadLogsByRealm(String realmName) {
        LOGGER.warning("loadLogsByRealm non supporté côté serveur pour le realm : " + realmName);
    }

    private String toIsoString(LocalDateTime ldt) {
        if (ldt == null) return null;
        return ldt.format(DATE_FORMATTER);
    }

    private void addSuccessMessage(String message) {
        FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message));
    }

    private void addErrorMessage(String message) {
        FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message));
    }
}
