package dev.lions.user.manager.resource;

import dev.lions.user.manager.api.AuditResourceApi;
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 dev.lions.user.manager.service.AuditService;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * REST Resource pour l'audit et la consultation des logs
 * Implémente l'interface API commune.
 */
@Slf4j
@jakarta.enterprise.context.ApplicationScoped
@jakarta.ws.rs.Path("/api/audit")
public class AuditResource implements AuditResourceApi {

    private static final String DEFAULT_REALM_VALUE = "master";

    @Inject
    AuditService auditService;

    @ConfigProperty(name = "lions.keycloak.admin-realm", defaultValue = DEFAULT_REALM_VALUE)
    String defaultRealm;

    @Override
    @RolesAllowed({ "admin", "auditor" })
    public List<AuditLogDTO> searchLogs(
            String acteurUsername,
            String dateDebutStr,
            String dateFinStr,
            TypeActionAudit typeAction,
            String ressourceType,
            Boolean succes,
            int page,
            int pageSize) {
        log.info("POST /api/audit/search - Recherche de logs");

        LocalDateTime dateDebut = dateDebutStr != null ? LocalDateTime.parse(dateDebutStr) : null;
        LocalDateTime dateFin = dateFinStr != null ? LocalDateTime.parse(dateFinStr) : null;

        // Utiliser findByActeur si acteurUsername est fourni, sinon findByRealm
        List<AuditLogDTO> logs;
        if (acteurUsername != null && !acteurUsername.isBlank()) {
            logs = auditService.findByActeur(acteurUsername, dateDebut, dateFin, page, pageSize);
        } else {
            // Pour une recherche générale, utiliser findByRealm (on utilise defaultRealm par
            // défaut)
            logs = auditService.findByRealm(defaultRealm, dateDebut, dateFin, page, pageSize);
        }

        // Filtrer par typeAction, ressourceType et succes si fournis
        if (typeAction != null || ressourceType != null || succes != null) {
            logs = logs.stream()
                    .filter(log -> typeAction == null || typeAction.equals(log.getTypeAction()))
                    .filter(log -> ressourceType == null || ressourceType.equals(log.getRessourceType()))
                    .filter(log -> succes == null || succes == log.isSuccessful())
                    .collect(Collectors.toList());
        }

        return logs;
    }

    @Override
    @RolesAllowed({ "admin", "auditor" })
    public List<AuditLogDTO> getLogsByActor(String acteurUsername, int limit) {
        log.info("GET /api/audit/actor/{} - Limite: {}", acteurUsername, limit);
        return auditService.findByActeur(acteurUsername, null, null, 0, limit);
    }

    @Override
    @RolesAllowed({ "admin", "auditor" })
    public List<AuditLogDTO> getLogsByResource(String ressourceType, String ressourceId, int limit) {
        log.info("GET /api/audit/resource/{}/{} - Limite: {}", ressourceType, ressourceId, limit);
        return auditService.findByRessource(ressourceType, ressourceId, null, null, 0, limit);
    }

    @Override
    @RolesAllowed({ "admin", "auditor" })
    public List<AuditLogDTO> getLogsByAction(TypeActionAudit typeAction, String dateDebutStr, String dateFinStr,
            int limit) {
        log.info("GET /api/audit/action/{} - Limite: {}", typeAction, limit);
        LocalDateTime dateDebut = dateDebutStr != null ? LocalDateTime.parse(dateDebutStr) : null;
        LocalDateTime dateFin = dateFinStr != null ? LocalDateTime.parse(dateFinStr) : null;

        return auditService.findByTypeAction(typeAction, defaultRealm, dateDebut, dateFin, 0, limit);
    }

    @Override
    @RolesAllowed({ "admin", "auditor" })
    public Map<TypeActionAudit, Long> getActionStatistics(String dateDebutStr, String dateFinStr) {
        log.info("GET /api/audit/stats/actions - Période: {} à {}", dateDebutStr, dateFinStr);
        LocalDateTime dateDebut = dateDebutStr != null ? LocalDateTime.parse(dateDebutStr) : null;
        LocalDateTime dateFin = dateFinStr != null ? LocalDateTime.parse(dateFinStr) : null;

        return auditService.countByActionType(defaultRealm, dateDebut, dateFin);
    }

    @Override
    @RolesAllowed({ "admin", "auditor" })
    public Map<String, Long> getUserActivityStatistics(String dateDebutStr, String dateFinStr) {
        log.info("GET /api/audit/stats/users - Période: {} à {}", dateDebutStr, dateFinStr);
        LocalDateTime dateDebut = dateDebutStr != null ? LocalDateTime.parse(dateDebutStr) : null;
        LocalDateTime dateFin = dateFinStr != null ? LocalDateTime.parse(dateFinStr) : null;

        return auditService.countByActeur(defaultRealm, dateDebut, dateFin);
    }

    @Override
    @RolesAllowed({ "admin", "auditor" })
    public CountDTO getFailureCount(String dateDebutStr, String dateFinStr) {
        log.info("GET /api/audit/stats/failures - Période: {} à {}", dateDebutStr, dateFinStr);
        LocalDateTime dateDebut = dateDebutStr != null ? LocalDateTime.parse(dateDebutStr) : null;
        LocalDateTime dateFin = dateFinStr != null ? LocalDateTime.parse(dateFinStr) : null;

        Map<String, Long> successVsFailure = auditService.countSuccessVsFailure(defaultRealm, dateDebut, dateFin);
        long count = successVsFailure.getOrDefault("failure", 0L);
        return new CountDTO(count);
    }

    @Override
    @RolesAllowed({ "admin", "auditor" })
    public CountDTO getSuccessCount(String dateDebutStr, String dateFinStr) {
        log.info("GET /api/audit/stats/success - Période: {} à {}", dateDebutStr, dateFinStr);
        LocalDateTime dateDebut = dateDebutStr != null ? LocalDateTime.parse(dateDebutStr) : null;
        LocalDateTime dateFin = dateFinStr != null ? LocalDateTime.parse(dateFinStr) : null;

        Map<String, Long> successVsFailure = auditService.countSuccessVsFailure(defaultRealm, dateDebut, dateFin);
        long count = successVsFailure.getOrDefault("success", 0L);
        return new CountDTO(count);
    }

    @Override
    @RolesAllowed({ "admin", "auditor" })
    public Response exportLogsToCSV(String dateDebutStr, String dateFinStr) {
        log.info("GET /api/audit/export/csv - Période: {} à {}", dateDebutStr, dateFinStr);

        try {
            LocalDateTime dateDebut = dateDebutStr != null ? LocalDateTime.parse(dateDebutStr) : null;
            LocalDateTime dateFin = dateFinStr != null ? LocalDateTime.parse(dateFinStr) : null;

            String csvContent = auditService.exportToCSV(defaultRealm, dateDebut, dateFin);

            return Response.ok(csvContent)
                    .header("Content-Disposition", "attachment; filename=\"audit-logs-" +
                            LocalDateTime.now().toString().replace(":", "-") + ".csv\"")
                    .build();
        } catch (Exception e) {
            log.error("Erreur lors de l'export CSV des logs", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    @RolesAllowed({ "admin" })
    public void purgeOldLogs(int joursAnciennete) {
        log.info("DELETE /api/audit/purge - Suppression des logs de plus de {} jours", joursAnciennete);
        LocalDateTime dateLimite = LocalDateTime.now().minusDays(joursAnciennete);
        auditService.purgeOldLogs(dateLimite);
    }
}
