package dev.lions.user.manager.service.impl;

import dev.lions.user.manager.dto.audit.AuditLogDTO;
import dev.lions.user.manager.enums.audit.TypeActionAudit;
import dev.lions.user.manager.server.impl.entity.AuditLogEntity;
import dev.lions.user.manager.server.impl.mapper.AuditLogMapper;
import dev.lions.user.manager.server.impl.repository.AuditLogRepository;
import io.quarkus.hibernate.orm.panache.PanacheQuery;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class AuditServiceImplTest {

    @Mock
    AuditLogRepository auditLogRepository;

    @Mock
    AuditLogMapper auditLogMapper;

    @InjectMocks
    AuditServiceImpl auditService;

    @BeforeEach
    void setUp() {
        auditService.auditEnabled = true;
        auditService.logToDatabase = true;
    }

    @Test
    void testLogAction() {
        AuditLogDTO log = new AuditLogDTO();
        log.setTypeAction(TypeActionAudit.USER_CREATE);
        log.setActeurUsername("admin");

        when(auditLogMapper.toEntity(any(AuditLogDTO.class))).thenReturn(new AuditLogEntity());

        auditService.logAction(log);

        verify(auditLogRepository).persist(any(AuditLogEntity.class));
    }

    @Test
    void testLogDisabled() {
        auditService.auditEnabled = false;
        AuditLogDTO log = new AuditLogDTO();

        auditService.logAction(log);

        verify(auditLogRepository, never()).persist(any(AuditLogEntity.class));
    }

    @Test
    void testLogSuccess() {
        when(auditLogMapper.toEntity(any(AuditLogDTO.class))).thenReturn(new AuditLogEntity());

        auditService.logSuccess(TypeActionAudit.USER_CREATE, "USER", "1", "user", "realm", "admin", "desc");

        verify(auditLogRepository).persist(any(AuditLogEntity.class));
    }

    @Test
    void testLogFailure() {
        when(auditLogMapper.toEntity(any(AuditLogDTO.class))).thenReturn(new AuditLogEntity());

        auditService.logFailure(TypeActionAudit.USER_CREATE, "USER", "1", "user", "realm", "admin", "ERR", "Error");

        verify(auditLogRepository).persist(any(AuditLogEntity.class));

        // Test findFailures mock logic
        when(auditLogRepository.search(anyString(), any(), any(), any(), any(), eq(false), anyInt(), anyInt()))
                .thenReturn(Collections.singletonList(new AuditLogEntity()));
        when(auditLogMapper.toDTOList(anyList())).thenReturn(Collections.singletonList(new AuditLogDTO()));

        List<AuditLogDTO> failures = auditService.findFailures("realm", null, null, 0, 10);
        assertEquals(1, failures.size());
    }

    @Test
    void testSearchLogs() {
        // Mocking repo results
        when(auditLogRepository.search(any(), anyString(), any(), any(), any(), any(), anyInt(), anyInt()))
                .thenReturn(Collections.singletonList(new AuditLogEntity()));
        when(auditLogMapper.toDTOList(anyList())).thenReturn(Collections.singletonList(new AuditLogDTO()));

        List<AuditLogDTO> byActeur = auditService.findByActeur("admin1", null, null, 0, 10);
        assertNotNull(byActeur);
        assertFalse(byActeur.isEmpty());

        when(auditLogRepository.search(anyString(), any(), any(), any(), anyString(), any(), anyInt(), anyInt()))
                .thenReturn(Collections.singletonList(new AuditLogEntity()));

        List<AuditLogDTO> byType = auditService.findByTypeAction(TypeActionAudit.ROLE_CREATE, "realm", null, null, 0,
                10);
        assertNotNull(byType);
    }

    @Test
    void testClearAll() {
        auditService.clearAll();
        verify(auditLogRepository).deleteAll();
    }
}
