package com.eactive.eai.manage.inflow;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.ResponseEntity;
import org.springframework.test.util.ReflectionTestUtils;

/**
 * InflowTargetMetricController 단위 테스트.
 *
 * <p>Spring MVC를 기동하지 않고 컨트롤러를 직접 인스턴스화하여
 * 응답 구조(success, data, count, message)를 검증한다.
 */
class InflowTargetMetricControllerTest {

    private InflowTargetMetricController controller;
    private InflowTargetMetricService mockService;

    @BeforeEach
    void setUp() {
        controller   = new InflowTargetMetricController();
        mockService  = mock(InflowTargetMetricService.class);
        ReflectionTestUtils.setField(controller, "metricService", mockService);
    }

    // -------------------------------------------------------------------------
    // Helper
    // -------------------------------------------------------------------------

    private TargetMetricDTO makeDTO(String targetId, String targetType,
                                    long allowed, long rejPs, long rejTh) {
        TargetMetricDTO dto = new TargetMetricDTO();
        dto.setTargetId(targetId);
        dto.setTargetType(targetType);
        dto.setActivate(true);
        dto.setAllowed(allowed);
        dto.setRejectedPerSecond(rejPs);
        dto.setRejectedThreshold(rejTh);
        long total = allowed + rejPs + rejTh;
        dto.setTotalRequests(total);
        dto.setRejectRatio(total > 0 ? (double)(rejPs + rejTh) / total * 100 : 0.0);
        return dto;
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> body(ResponseEntity<?> response) {
        return (Map<String, Object>) response.getBody();
    }

    // =========================================================================
    // 어댑터 — 단일 조회
    // =========================================================================

    @Test
    void getAdapterMetric_found_successTrueAndDataPresent() {
        TargetMetricDTO dto = makeDTO("A1", "ADAPTER", 900, 60, 40);
        when(mockService.getAdapterMetric("A1")).thenReturn(dto);

        ResponseEntity<?> response = controller.getAdapterMetric("A1");
        Map<String, Object> body = body(response);

        assertEquals(200, response.getStatusCodeValue());
        assertEquals(Boolean.TRUE, body.get("success"));
        assertSame(dto, body.get("data"));
        assertFalse(body.containsKey("message"));
    }

    @Test
    void getAdapterMetric_notFound_successFalseWithMessage() {
        when(mockService.getAdapterMetric("GHOST")).thenReturn(null);

        Map<String, Object> body = body(controller.getAdapterMetric("GHOST"));

        assertEquals(Boolean.FALSE, body.get("success"));
        assertTrue(body.get("message").toString().contains("GHOST"));
    }

    // =========================================================================
    // 어댑터 — 전체 조회
    // =========================================================================

    @Test
    void getAllAdapterMetrics_returnsListAndCount() {
        List<TargetMetricDTO> list = Arrays.asList(
            makeDTO("A1", "ADAPTER", 100, 5, 0),
            makeDTO("A2", "ADAPTER", 200, 0, 10)
        );
        when(mockService.getAllAdapterMetrics()).thenReturn(list);

        Map<String, Object> body = body(controller.getAllAdapterMetrics());

        assertEquals(Boolean.TRUE, body.get("success"));
        assertSame(list, body.get("data"));
        assertEquals(2, body.get("count"));
    }

    @Test
    void getAllAdapterMetrics_emptyList_countZero() {
        when(mockService.getAllAdapterMetrics()).thenReturn(Collections.emptyList());

        Map<String, Object> body = body(controller.getAllAdapterMetrics());

        assertEquals(Boolean.TRUE, body.get("success"));
        assertEquals(0, body.get("count"));
    }

    // =========================================================================
    // 어댑터 — reset
    // =========================================================================

    @Test
    void resetAdapterMetric_success_successTrueWithTargetId() {
        when(mockService.resetAdapterMetric("A1")).thenReturn(true);

        Map<String, Object> body = body(controller.resetAdapterMetric("A1"));

        assertEquals(Boolean.TRUE, body.get("success"));
        assertTrue(body.get("message").toString().contains("A1"));
    }

    @Test
    void resetAdapterMetric_notFound_successFalseWithTargetId() {
        when(mockService.resetAdapterMetric("GHOST")).thenReturn(false);

        Map<String, Object> body = body(controller.resetAdapterMetric("GHOST"));

        assertEquals(Boolean.FALSE, body.get("success"));
        assertTrue(body.get("message").toString().contains("GHOST"));
    }

    @Test
    void resetAllAdapterMetrics_alwaysSuccessTrue() {
        doNothing().when(mockService).resetAllAdapterMetrics();

        Map<String, Object> body = body(controller.resetAllAdapterMetrics());

        assertEquals(Boolean.TRUE, body.get("success"));
        assertNotNull(body.get("message"));
        verify(mockService).resetAllAdapterMetrics();
    }

    // =========================================================================
    // 인터페이스 — 단일 조회
    // =========================================================================

    @Test
    void getInterfaceMetric_found_successTrueAndDataPresent() {
        TargetMetricDTO dto = makeDTO("IF1", "INTERFACE", 500, 20, 10);
        when(mockService.getInterfaceMetric("IF1")).thenReturn(dto);

        Map<String, Object> body = body(controller.getInterfaceMetric("IF1"));

        assertEquals(Boolean.TRUE, body.get("success"));
        assertSame(dto, body.get("data"));
    }

    @Test
    void getInterfaceMetric_notFound_successFalseWithMessage() {
        when(mockService.getInterfaceMetric("GHOST")).thenReturn(null);

        Map<String, Object> body = body(controller.getInterfaceMetric("GHOST"));

        assertEquals(Boolean.FALSE, body.get("success"));
        assertTrue(body.get("message").toString().contains("GHOST"));
    }

    // =========================================================================
    // 인터페이스 — 전체 조회
    // =========================================================================

    @Test
    void getAllInterfaceMetrics_returnsListAndCount() {
        List<TargetMetricDTO> list = Collections.singletonList(
            makeDTO("IF1", "INTERFACE", 100, 0, 0));
        when(mockService.getAllInterfaceMetrics()).thenReturn(list);

        Map<String, Object> body = body(controller.getAllInterfaceMetrics());

        assertEquals(Boolean.TRUE, body.get("success"));
        assertEquals(1, body.get("count"));
    }

    // =========================================================================
    // 인터페이스 — reset
    // =========================================================================

    @Test
    void resetInterfaceMetric_success_successTrue() {
        when(mockService.resetInterfaceMetric("IF1")).thenReturn(true);

        Map<String, Object> body = body(controller.resetInterfaceMetric("IF1"));

        assertEquals(Boolean.TRUE, body.get("success"));
        assertTrue(body.get("message").toString().contains("IF1"));
    }

    @Test
    void resetAllInterfaceMetrics_callsDelegateOnce() {
        doNothing().when(mockService).resetAllInterfaceMetrics();

        controller.resetAllInterfaceMetrics();

        verify(mockService, times(1)).resetAllInterfaceMetrics();
    }
}
