package cn.novalon.gym.manage.notify.handler;

import cn.novalon.gym.manage.notify.core.domain.SysNotice;
import cn.novalon.gym.manage.notify.core.service.ISysNoticeService;
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.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class SysNoticeHandlerTest {

    @Mock
    private ISysNoticeService noticeService;

    private SysNoticeHandler noticeHandler;
    private SysNotice testNotice;

    @BeforeEach
    void setUp() {
        noticeHandler = new SysNoticeHandler(noticeService);
        
        testNotice = new SysNotice();
        testNotice.setId(1L);
        testNotice.setNoticeTitle("系统维护通知");
        testNotice.setNoticeType("SYSTEM");
        testNotice.setNoticeContent("系统将于今晚进行维护");
        testNotice.setStatus("PUBLISHED");
        testNotice.setCreateBy("admin");
        testNotice.setCreatedAt(LocalDateTime.now());
    }

    @Test
    void testGetAllNotices() {
        when(noticeService.getAllNotices()).thenReturn(Flux.just(testNotice));
        
        ServerRequest request = MockServerRequest.builder().build();
        Mono<ServerResponse> response = noticeHandler.getAllNotices(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(noticeService).getAllNotices();
    }

    @Test
    void testGetNoticeById() {
        when(noticeService.getNoticeById(1L)).thenReturn(Mono.just(testNotice));
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .build();
        Mono<ServerResponse> response = noticeHandler.getNoticeById(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(noticeService).getNoticeById(1L);
    }

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

    @Test
    void testGetNoticesByStatus() {
        when(noticeService.getNoticesByStatus("PUBLISHED")).thenReturn(Flux.just(testNotice));
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("status", "PUBLISHED")
                .build();
        Mono<ServerResponse> response = noticeHandler.getNoticesByStatus(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(noticeService).getNoticesByStatus("PUBLISHED");
    }

    @Test
    void testGetNoticesByStatus_Draft() {
        when(noticeService.getNoticesByStatus("DRAFT")).thenReturn(Flux.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("status", "DRAFT")
                .build();
        Mono<ServerResponse> response = noticeHandler.getNoticesByStatus(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(noticeService).getNoticesByStatus("DRAFT");
    }

    @Test
    void testCreateNotice() {
        SysNotice newNotice = new SysNotice();
        newNotice.setNoticeTitle("新通知");
        newNotice.setNoticeType("1");
        newNotice.setNoticeContent("测试内容");
        newNotice.setStatus("0");
        
        when(noticeService.createNotice(any(SysNotice.class))).thenReturn(Mono.just(testNotice));
        
        ServerRequest request = MockServerRequest.builder()
                .body(Mono.just(newNotice));
        Mono<ServerResponse> response = noticeHandler.createNotice(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.CREATED)
                .verifyComplete();
        
        verify(noticeService).createNotice(any(SysNotice.class));
    }

    @Test
    void testCreateNotice_WithAllFields() {
        SysNotice newNotice = new SysNotice();
        newNotice.setNoticeTitle("完整通知");
        newNotice.setNoticeType("2");
        newNotice.setNoticeContent("完整内容");
        newNotice.setStatus("1");
        newNotice.setCreateBy("admin");
        
        when(noticeService.createNotice(any(SysNotice.class))).thenReturn(Mono.just(testNotice));
        
        ServerRequest request = MockServerRequest.builder()
                .body(Mono.just(newNotice));
        Mono<ServerResponse> response = noticeHandler.createNotice(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.CREATED)
                .verifyComplete();
        
        verify(noticeService).createNotice(any(SysNotice.class));
    }

    @Test
    void testUpdateNotice() {
        SysNotice updateNotice = new SysNotice();
        updateNotice.setNoticeTitle("更新后的通知");
        updateNotice.setNoticeType("SYSTEM");
        updateNotice.setNoticeContent("更新后的内容");
        updateNotice.setStatus("PUBLISHED");
        
        when(noticeService.updateNotice(anyLong(), any(SysNotice.class))).thenReturn(Mono.just(testNotice));
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .body(Mono.just(updateNotice));
        Mono<ServerResponse> response = noticeHandler.updateNotice(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.OK)
                .verifyComplete();
        
        verify(noticeService).updateNotice(1L, updateNotice);
    }

    @Test
    void testUpdateNotice_NotFound() {
        SysNotice updateNotice = new SysNotice();
        updateNotice.setNoticeTitle("更新后的通知");
        
        when(noticeService.updateNotice(anyLong(), any(SysNotice.class))).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "999")
                .body(Mono.just(updateNotice));
        Mono<ServerResponse> response = noticeHandler.updateNotice(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NOT_FOUND)
                .verifyComplete();
        
        verify(noticeService).updateNotice(999L, updateNotice);
    }

    @Test
    void testDeleteNotice() {
        when(noticeService.getNoticeById(1L)).thenReturn(Mono.just(testNotice));
        when(noticeService.deleteNotice(1L)).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "1")
                .build();
        Mono<ServerResponse> response = noticeHandler.deleteNotice(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NO_CONTENT)
                .verifyComplete();
        
        verify(noticeService).getNoticeById(1L);
        verify(noticeService).deleteNotice(1L);
    }

    @Test
    void testDeleteNotice_NotFound() {
        when(noticeService.getNoticeById(999L)).thenReturn(Mono.empty());
        
        ServerRequest request = MockServerRequest.builder()
                .pathVariable("id", "999")
                .build();
        Mono<ServerResponse> response = noticeHandler.deleteNotice(request);
        
        StepVerifier.create(response)
                .expectNextMatches(serverResponse -> 
                    serverResponse.statusCode() == HttpStatus.NOT_FOUND)
                .verifyComplete();
        
        verify(noticeService).getNoticeById(999L);
    }
}
