package cn.novalon.gym.manage.sys.handler.log;

import cn.novalon.gym.manage.sys.core.domain.OperationLog;
import cn.novalon.gym.manage.sys.core.query.OperationLogQuery;
import cn.novalon.gym.manage.sys.core.service.IOperationLogService;
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 org.springframework.http.HttpStatus;
import org.springframework.mock.web.reactive.function.server.MockServerRequest;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
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 OperationLogHandlerTest {

    @Mock
    private IOperationLogService logService;

    private OperationLogHandler logHandler;
    private OperationLog testOperationLog;

    @BeforeEach
    void setUp() {
        logHandler = new OperationLogHandler(logService);

        testOperationLog = new OperationLog();
        testOperationLog.setId(1L);
        testOperationLog.setUsername("testuser");
        testOperationLog.setOperation("测试操作");
        testOperationLog.setMethod("testMethod");
        testOperationLog.setParams("test params");
        testOperationLog.setDuration(100L);
        testOperationLog.setIp("192.168.1.1");
        testOperationLog.setCreatedAt(LocalDateTime.now());
    }

    @Test
    void testGetAllOperationLogs() {
        when(logService.findAll()).thenReturn(Flux.just(testOperationLog));

        ServerRequest request = MockServerRequest.builder().build();
        Mono<ServerResponse> response = logHandler.getAllOperationLogs(request);

        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();

        verify(logService).findAll();
    }

    @Test
    void testGetOperationLogById() {
        when(logService.findById(1L)).thenReturn(Mono.just(testOperationLog));

        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .build();
        Mono<ServerResponse> response = logHandler.getOperationLogById(request);

        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();

        verify(logService).findById(1L);
    }

    @Test
    void testGetOperationLogById_NotFound() {
        when(logService.findById(999L)).thenReturn(Mono.empty());

        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "999")
                .build();
        Mono<ServerResponse> response = logHandler.getOperationLogById(request);

        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> serverResponse.statusCode() == HttpStatus.NOT_FOUND)
                .verifyComplete();

        verify(logService).findById(999L);
    }

    @Test
    void testGetOperationLogsByPage() {
        PageResponse<OperationLog> pageResponse = new PageResponse<>();
        pageResponse.setContent(java.util.Collections.singletonList(testOperationLog));
        pageResponse.setTotalElements(1L);
        pageResponse.setTotalPages(1);
        pageResponse.setPageSize(10);
        pageResponse.setCurrentPage(0);

        when(logService.findByQueryWithPagination(any(OperationLogQuery.class), any(PageRequest.class)))
                .thenReturn(Mono.just(pageResponse));

        ServerRequest request = MockServerRequest.builder()
                .queryParam("page", "0")
                .queryParam("size", "10")
                .queryParam("sort", "createdAt")
                .queryParam("order", "desc")
                .build();
        Mono<ServerResponse> response = logHandler.getOperationLogsByPage(request);

        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();

        verify(logService).findByQueryWithPagination(any(OperationLogQuery.class), any(PageRequest.class));
    }

    @Test
    void testGetOperationLogsByPageWithKeyword() {
        PageResponse<OperationLog> pageResponse = new PageResponse<>();
        pageResponse.setContent(java.util.Collections.singletonList(testOperationLog));
        pageResponse.setTotalElements(1L);
        pageResponse.setTotalPages(1);
        pageResponse.setPageSize(10);
        pageResponse.setCurrentPage(0);

        when(logService.findByQueryWithPagination(any(OperationLogQuery.class), any(PageRequest.class)))
                .thenReturn(Mono.just(pageResponse));

        ServerRequest request = MockServerRequest.builder()
                .queryParam("page", "0")
                .queryParam("size", "10")
                .queryParam("sort", "createdAt")
                .queryParam("order", "desc")
                .queryParam("keyword", "test")
                .build();
        Mono<ServerResponse> response = logHandler.getOperationLogsByPage(request);

        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();

        verify(logService).findByQueryWithPagination(any(OperationLogQuery.class), any(PageRequest.class));
    }

    @Test
    void testGetOperationLogCount() {
        when(logService.count()).thenReturn(Mono.just(100L));

        ServerRequest request = MockServerRequest.builder().build();
        Mono<ServerResponse> response = logHandler.getOperationLogCount(request);

        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();

        verify(logService).count();
    }

    @Test
    void testCreateOperationLog() {
        when(logService.save(any(OperationLog.class))).thenReturn(Mono.just(testOperationLog));

        ServerRequest request = MockServerRequest.builder()
                .body(Mono.just(testOperationLog));
        Mono<ServerResponse> response = logHandler.createOperationLog(request);

        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> serverResponse.statusCode() == HttpStatus.CREATED)
                .verifyComplete();

        verify(logService).save(any(OperationLog.class));
    }
}
