package cn.novalon.gym.manage.sys.core.service.impl;

import cn.novalon.gym.manage.sys.core.domain.SysExceptionLog;
import cn.novalon.gym.manage.sys.core.repository.ISysExceptionLogRepository;
import cn.novalon.gym.manage.common.dto.PageRequest;
import cn.novalon.gym.manage.common.dto.PageResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import java.time.LocalDateTime;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class SysExceptionLogServiceTest {

    @Mock
    private ISysExceptionLogRepository repository;

    private SysExceptionLogService exceptionLogService;
    private SysExceptionLog testExceptionLog;

    @BeforeEach
    void setUp() {
        exceptionLogService = new SysExceptionLogService(repository);
        
        testExceptionLog = new SysExceptionLog();
        testExceptionLog.setId(1L);
        testExceptionLog.setUsername("testuser");
        testExceptionLog.setTitle("test operation");
        testExceptionLog.setExceptionName("NullPointerException");
        testExceptionLog.setExceptionMsg("Test exception");
        testExceptionLog.setCreateTime(LocalDateTime.now());
    }

    @Test
    void testFindAll() {
        when(repository.findAllByOrderByCreateTimeDesc()).thenReturn(Flux.just(testExceptionLog));
        
        Flux<SysExceptionLog> result = exceptionLogService.findAll();
        
        StepVerifier.create(result)
                .expectNext(testExceptionLog)
                .verifyComplete();
        
        verify(repository).findAllByOrderByCreateTimeDesc();
    }

    @Test
    void testFindByUsername() {
        when(repository.findByUsernameOrderByCreateTimeDesc("testuser")).thenReturn(Flux.just(testExceptionLog));
        
        Flux<SysExceptionLog> result = exceptionLogService.findByUsername("testuser");
        
        StepVerifier.create(result)
                .expectNext(testExceptionLog)
                .verifyComplete();
        
        verify(repository).findByUsernameOrderByCreateTimeDesc("testuser");
    }

    @Test
    void testFindByCreateTimeBetween() {
        LocalDateTime startTime = LocalDateTime.now().minusDays(1);
        LocalDateTime endTime = LocalDateTime.now();
        
        when(repository.findByCreateTimeBetweenOrderByCreateTimeDesc(startTime, endTime))
                .thenReturn(Flux.just(testExceptionLog));
        
        Flux<SysExceptionLog> result = exceptionLogService.findByCreateTimeBetween(startTime, endTime);
        
        StepVerifier.create(result)
                .expectNext(testExceptionLog)
                .verifyComplete();
        
        verify(repository).findByCreateTimeBetweenOrderByCreateTimeDesc(startTime, endTime);
    }

    @Test
    void testSave() {
        when(repository.save(any(SysExceptionLog.class))).thenReturn(Mono.just(testExceptionLog));
        
        Mono<SysExceptionLog> result = exceptionLogService.save(testExceptionLog);
        
        StepVerifier.create(result)
                .expectNext(testExceptionLog)
                .verifyComplete();
        
        verify(repository).save(any(SysExceptionLog.class));
    }

    @Test
    void testFindById() {
        when(repository.findById(1L)).thenReturn(Mono.just(testExceptionLog));
        
        Mono<SysExceptionLog> result = exceptionLogService.findById(1L);
        
        StepVerifier.create(result)
                .expectNext(testExceptionLog)
                .verifyComplete();
        
        verify(repository).findById(1L);
    }

    @Test
    void testFindExceptionLogsByPage() {
        PageRequest pageRequest = new PageRequest();
        pageRequest.setPage(0);
        pageRequest.setSize(10);
        
        PageResponse<SysExceptionLog> pageResponse = new PageResponse<>();
        pageResponse.setContent(java.util.List.of(testExceptionLog));
        pageResponse.setTotalElements(1L);
        pageResponse.setTotalPages(1);
        
        when(repository.findExceptionLogsByPage(pageRequest)).thenReturn(Mono.just(pageResponse));
        
        Mono<PageResponse<SysExceptionLog>> result = exceptionLogService.findExceptionLogsByPage(pageRequest);
        
        StepVerifier.create(result)
                .expectNextMatches(response -> 
                    response.getTotalElements() == 1L &&
                    response.getTotalPages() == 1 &&
                    response.getContent().size() == 1)
                .verifyComplete();
        
        verify(repository).findExceptionLogsByPage(pageRequest);
    }

    @Test
    void testFindExceptionLogsByPage_WithKeyword() {
        PageRequest pageRequest = new PageRequest();
        pageRequest.setPage(0);
        pageRequest.setSize(10);
        pageRequest.setKeyword("test");
        
        PageResponse<SysExceptionLog> pageResponse = new PageResponse<>();
        pageResponse.setContent(java.util.List.of(testExceptionLog));
        pageResponse.setTotalElements(1L);
        pageResponse.setTotalPages(1);
        
        when(repository.findExceptionLogsByPage(pageRequest)).thenReturn(Mono.just(pageResponse));
        
        Mono<PageResponse<SysExceptionLog>> result = exceptionLogService.findExceptionLogsByPage(pageRequest);
        
        StepVerifier.create(result)
                .expectNextMatches(response -> 
                    response.getTotalElements() == 1L &&
                    response.getContent().size() == 1)
                .verifyComplete();
        
        verify(repository).findExceptionLogsByPage(pageRequest);
    }

    @Test
    void testFindExceptionLogsByPage_WithSort() {
        PageRequest pageRequest = new PageRequest();
        pageRequest.setPage(0);
        pageRequest.setSize(10);
        pageRequest.setSort("username");
        pageRequest.setOrder("desc");
        
        PageResponse<SysExceptionLog> pageResponse = new PageResponse<>();
        pageResponse.setContent(java.util.List.of(testExceptionLog));
        pageResponse.setTotalElements(1L);
        pageResponse.setTotalPages(1);
        
        when(repository.findExceptionLogsByPage(pageRequest)).thenReturn(Mono.just(pageResponse));
        
        Mono<PageResponse<SysExceptionLog>> result = exceptionLogService.findExceptionLogsByPage(pageRequest);
        
        StepVerifier.create(result)
                .expectNextMatches(response -> 
                    response.getTotalElements() == 1L &&
                    response.getContent().size() == 1)
                .verifyComplete();
        
        verify(repository).findExceptionLogsByPage(pageRequest);
    }

    @Test
    void testCount() {
        when(repository.count()).thenReturn(Mono.just(50L));
        
        Mono<Long> result = exceptionLogService.count();
        
        StepVerifier.create(result)
                .expectNext(50L)
                .verifyComplete();
        
        verify(repository).count();
    }
}