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

import cn.novalon.gym.manage.sys.core.domain.SysLoginLog;
import cn.novalon.gym.manage.sys.core.repository.ISysLoginLogRepository;
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 SysLoginLogServiceTest {

    @Mock
    private ISysLoginLogRepository repository;

    private SysLoginLogService loginLogService;
    private SysLoginLog testLoginLog;

    @BeforeEach
    void setUp() {
        loginLogService = new SysLoginLogService(repository);
        
        testLoginLog = new SysLoginLog();
        testLoginLog.setId(1L);
        testLoginLog.setUsername("testuser");
        testLoginLog.setIp("192.168.1.1");
        testLoginLog.setLocation("北京");
        testLoginLog.setBrowser("Chrome");
        testLoginLog.setOs("Windows");
        testLoginLog.setStatus("1");
        testLoginLog.setMessage("登录成功");
        testLoginLog.setLoginTime(LocalDateTime.now());
    }

    @Test
    void testFindAll() {
        when(repository.findAllByOrderByLoginTimeDesc()).thenReturn(Flux.just(testLoginLog));
        
        Flux<SysLoginLog> result = loginLogService.findAll();
        
        StepVerifier.create(result)
                .expectNext(testLoginLog)
                .verifyComplete();
        
        verify(repository).findAllByOrderByLoginTimeDesc();
    }

    @Test
    void testFindByUsername() {
        when(repository.findByUsernameOrderByLoginTimeDesc("testuser")).thenReturn(Flux.just(testLoginLog));
        
        Flux<SysLoginLog> result = loginLogService.findByUsername("testuser");
        
        StepVerifier.create(result)
                .expectNext(testLoginLog)
                .verifyComplete();
        
        verify(repository).findByUsernameOrderByLoginTimeDesc("testuser");
    }

    @Test
    void testFindByLoginTimeBetween() {
        LocalDateTime startTime = LocalDateTime.now().minusDays(1);
        LocalDateTime endTime = LocalDateTime.now();
        
        when(repository.findByLoginTimeBetweenOrderByLoginTimeDesc(startTime, endTime))
                .thenReturn(Flux.just(testLoginLog));
        
        Flux<SysLoginLog> result = loginLogService.findByLoginTimeBetween(startTime, endTime);
        
        StepVerifier.create(result)
                .expectNext(testLoginLog)
                .verifyComplete();
        
        verify(repository).findByLoginTimeBetweenOrderByLoginTimeDesc(startTime, endTime);
    }

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

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

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

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

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

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