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

import cn.novalon.gym.manage.sys.core.domain.SysDictType;
import cn.novalon.gym.manage.sys.core.domain.SysDictData;
import cn.novalon.gym.manage.sys.core.service.ISysDictTypeService;
import cn.novalon.gym.manage.sys.core.service.ISysDictDataService;
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 SysDictHandlerTest {

    @Mock
    private ISysDictTypeService dictTypeService;

    @Mock
    private ISysDictDataService dictDataService;

    private SysDictHandler dictHandler;
    private SysDictType testDictType;
    private SysDictData testDictData;

    @BeforeEach
    void setUp() {
        dictHandler = new SysDictHandler(dictTypeService, dictDataService);
        
        testDictType = new SysDictType();
        testDictType.setId(1L);
        testDictType.setDictName("用户状态");
        testDictType.setDictType("user_status");
        testDictType.setStatus("1");
        testDictType.setRemark("用户状态字典");
        testDictType.setCreatedAt(LocalDateTime.now());
        testDictType.setUpdatedAt(LocalDateTime.now());
        
        testDictData = new SysDictData();
        testDictData.setId(1L);
        testDictData.setDictType("user_status");
        testDictData.setDictLabel("正常");
        testDictData.setDictValue("1");
        testDictData.setDictSort(1);
        testDictData.setStatus("1");
        testDictData.setCreatedAt(LocalDateTime.now());
        testDictData.setUpdatedAt(LocalDateTime.now());
    }

    @Test
    void testGetAllDictTypes() {
        when(dictTypeService.findAll()).thenReturn(Flux.just(testDictType));
        
        ServerRequest request = MockServerRequest.builder().build();
        Mono<ServerResponse> response = dictHandler.getAllDictTypes(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(dictTypeService).findAll();
    }

    @Test
    void testGetDictTypeById() {
        when(dictTypeService.findById(1L)).thenReturn(Mono.just(testDictType));
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .build();
        Mono<ServerResponse> response = dictHandler.getDictTypeById(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(dictTypeService).findById(1L);
    }

    @Test
    void testGetDictTypeById_NotFound() {
        when(dictTypeService.findById(999L)).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "999")
                .build();
        Mono<ServerResponse> response = dictHandler.getDictTypeById(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NOT_FOUND)
                .verifyComplete();
        
        verify(dictTypeService).findById(999L);
    }

    @Test
    void testGetDictTypeByType() {
        when(dictTypeService.findByDictType("user_status")).thenReturn(Mono.just(testDictType));
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("dictType", "user_status")
                .build();
        Mono<ServerResponse> response = dictHandler.getDictTypeByType(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(dictTypeService).findByDictType("user_status");
    }

    @Test
    void testGetDictTypeByType_NotFound() {
        when(dictTypeService.findByDictType("unknown")).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("dictType", "unknown")
                .build();
        Mono<ServerResponse> response = dictHandler.getDictTypeByType(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NOT_FOUND)
                .verifyComplete();
        
        verify(dictTypeService).findByDictType("unknown");
    }

    @Test
    void testCreateDictType() {
        SysDictType newDictType = new SysDictType();
        newDictType.setDictName("新字典");
        newDictType.setDictType("new_dict");
        newDictType.setStatus("1");
        
        when(dictTypeService.save(any())).thenReturn(Mono.just(testDictType));
        
        ServerRequest request = MockServerRequest.builder()
                .body(Mono.just(newDictType));
        Mono<ServerResponse> response = dictHandler.createDictType(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.CREATED)
                .verifyComplete();
        
        verify(dictTypeService).save(any());
    }

    @Test
    void testUpdateDictType() {
        SysDictType updateDictType = new SysDictType();
        updateDictType.setDictName("更新字典");
        updateDictType.setStatus("0");
        
        when(dictTypeService.findById(1L)).thenReturn(Mono.just(testDictType));
        when(dictTypeService.save(any())).thenReturn(Mono.just(testDictType));
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .body(Mono.just(updateDictType));
        Mono<ServerResponse> response = dictHandler.updateDictType(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(dictTypeService).findById(1L);
        verify(dictTypeService).save(any());
    }

    @Test
    void testUpdateDictType_NotFound() {
        SysDictType updateDictType = new SysDictType();
        updateDictType.setDictName("更新字典");
        
        when(dictTypeService.findById(999L)).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "999")
                .body(Mono.just(updateDictType));
        Mono<ServerResponse> response = dictHandler.updateDictType(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NOT_FOUND)
                .verifyComplete();
        
        verify(dictTypeService).findById(999L);
    }

    @Test
    void testDeleteDictType() {
        when(dictTypeService.deleteById(1L)).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .build();
        Mono<ServerResponse> response = dictHandler.deleteDictType(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NO_CONTENT)
                .verifyComplete();
        
        verify(dictTypeService).deleteById(1L);
    }

    @Test
    void testGetAllDictData() {
        when(dictDataService.findAll()).thenReturn(Flux.just(testDictData));
        
        ServerRequest request = MockServerRequest.builder().build();
        Mono<ServerResponse> response = dictHandler.getAllDictData(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(dictDataService).findAll();
    }

    @Test
    void testGetDictDataById() {
        when(dictDataService.findById(1L)).thenReturn(Mono.just(testDictData));
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .build();
        Mono<ServerResponse> response = dictHandler.getDictDataById(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(dictDataService).findById(1L);
    }

    @Test
    void testGetDictDataById_NotFound() {
        when(dictDataService.findById(999L)).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "999")
                .build();
        Mono<ServerResponse> response = dictHandler.getDictDataById(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NOT_FOUND)
                .verifyComplete();
        
        verify(dictDataService).findById(999L);
    }

    @Test
    void testGetDictDataByType() {
        when(dictDataService.findByDictType("user_status")).thenReturn(Flux.just(testDictData));
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("dictType", "user_status")
                .build();
        Mono<ServerResponse> response = dictHandler.getDictDataByType(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(dictDataService).findByDictType("user_status");
    }

    @Test
    void testCreateDictData() {
        SysDictData newDictData = new SysDictData();
        newDictData.setDictType("user_status");
        newDictData.setDictLabel("新状态");
        newDictData.setDictValue("2");
        newDictData.setDictSort(2);
        newDictData.setStatus("1");
        
        when(dictDataService.save(any())).thenReturn(Mono.just(testDictData));
        
        ServerRequest request = MockServerRequest.builder()
                .body(Mono.just(newDictData));
        Mono<ServerResponse> response = dictHandler.createDictData(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.CREATED)
                .verifyComplete();
        
        verify(dictDataService).save(any());
    }

    @Test
    void testUpdateDictData() {
        SysDictData updateDictData = new SysDictData();
        updateDictData.setDictLabel("更新状态");
        updateDictData.setDictValue("3");
        updateDictData.setDictSort(3);
        updateDictData.setStatus("0");
        
        when(dictDataService.findById(1L)).thenReturn(Mono.just(testDictData));
        when(dictDataService.save(any())).thenReturn(Mono.just(testDictData));
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .body(Mono.just(updateDictData));
        Mono<ServerResponse> response = dictHandler.updateDictData(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(dictDataService).findById(1L);
        verify(dictDataService).save(any());
    }

    @Test
    void testUpdateDictData_NotFound() {
        SysDictData updateDictData = new SysDictData();
        updateDictData.setDictLabel("更新状态");
        
        when(dictDataService.findById(999L)).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "999")
                .body(Mono.just(updateDictData));
        Mono<ServerResponse> response = dictHandler.updateDictData(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NOT_FOUND)
                .verifyComplete();
        
        verify(dictDataService).findById(999L);
    }

    @Test
    void testDeleteDictData() {
        when(dictDataService.deleteById(1L)).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .build();
        Mono<ServerResponse> response = dictHandler.deleteDictData(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NO_CONTENT)
                .verifyComplete();
        
        verify(dictDataService).deleteById(1L);
    }
}