package com.ycwl.basic.puzzle.fill.datasource;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

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

/**
 * 设备图片数据源策略测试
 */
@DisplayName("设备图片数据源策略测试")
@ExtendWith(MockitoExtension.class)
class DeviceImageDataSourceStrategyTest {

    @Mock
    private SourceMapper sourceMapper;

    @InjectMocks
    private DeviceImageDataSourceStrategy strategy;

    private ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        objectMapper = new ObjectMapper();
    }

    @Test
    @DisplayName("应该返回正确的支持类型")
    void shouldReturnCorrectSupportedType() {
        assertEquals("DEVICE_IMAGE", strategy.getSupportedType());
    }

    @Test
    @DisplayName("应该返回指定设备的图片URL")
    void shouldReturnDeviceImageUrl() throws Exception {
        // Given
        Long faceId = 123L;
        Integer deviceIndex = 0;
        String expectedUrl = "https://oss.example.com/device/img1.jpg";

        SourceEntity source = new SourceEntity();
        source.setId(1L);
        source.setType(2); // 图片类型
        source.setUrl(expectedUrl);

        when(sourceMapper.getSourceByFaceAndDeviceIndex(faceId, deviceIndex, 2, "LATEST"))
                .thenReturn(source);

        DataSourceContext context = DataSourceContext.builder()
                .faceId(faceId)
                .build();

        JsonNode sourceFilter = objectMapper.readTree("{\"type\": 2, \"deviceIndex\": 0}");

        // When
        String result = strategy.resolve(sourceFilter, "LATEST", context);

        // Then
        assertEquals(expectedUrl, result);
        verify(sourceMapper, times(1)).getSourceByFaceAndDeviceIndex(faceId, deviceIndex, 2, "LATEST");
    }

    @Test
    @DisplayName("当type为1(视频)时应该返回videoUrl")
    void shouldReturnVideoUrlWhenTypeIs1() throws Exception {
        // Given
        Long faceId = 123L;
        Integer deviceIndex = 1;
        String expectedUrl = "https://oss.example.com/device/video1.mp4";

        SourceEntity source = new SourceEntity();
        source.setId(2L);
        source.setType(1); // 视频类型
        source.setVideoUrl(expectedUrl);

        when(sourceMapper.getSourceByFaceAndDeviceIndex(faceId, deviceIndex, 1, "LATEST"))
                .thenReturn(source);

        DataSourceContext context = DataSourceContext.builder()
                .faceId(faceId)
                .build();

        JsonNode sourceFilter = objectMapper.readTree("{\"type\": 1, \"deviceIndex\": 1}");

        // When
        String result = strategy.resolve(sourceFilter, "LATEST", context);

        // Then
        assertEquals(expectedUrl, result);
    }

    @Test
    @DisplayName("当未指定type时应该默认使用type=2(图片)")
    void shouldDefaultToImageTypeWhenTypeNotSpecified() throws Exception {
        // Given
        Long faceId = 123L;
        Integer deviceIndex = 0;

        SourceEntity source = new SourceEntity();
        source.setType(2);
        source.setUrl("https://oss.example.com/default.jpg");

        when(sourceMapper.getSourceByFaceAndDeviceIndex(faceId, deviceIndex, 2, "LATEST"))
                .thenReturn(source);

        DataSourceContext context = DataSourceContext.builder()
                .faceId(faceId)
                .build();

        JsonNode sourceFilter = objectMapper.readTree("{\"deviceIndex\": 0}");

        // When
        strategy.resolve(sourceFilter, "LATEST", context);

        // Then
        verify(sourceMapper, times(1)).getSourceByFaceAndDeviceIndex(eq(faceId), eq(deviceIndex), eq(2), anyString());
    }

    @Test
    @DisplayName("当未指定deviceIndex时应该默认使用0")
    void shouldDefaultToZeroWhenDeviceIndexNotSpecified() throws Exception {
        // Given
        Long faceId = 123L;

        SourceEntity source = new SourceEntity();
        source.setType(2);
        source.setUrl("https://oss.example.com/default.jpg");

        when(sourceMapper.getSourceByFaceAndDeviceIndex(faceId, 0, 2, "LATEST"))
                .thenReturn(source);

        DataSourceContext context = DataSourceContext.builder()
                .faceId(faceId)
                .build();

        JsonNode sourceFilter = objectMapper.readTree("{\"type\": 2}");

        // When
        strategy.resolve(sourceFilter, "LATEST", context);

        // Then
        verify(sourceMapper, times(1)).getSourceByFaceAndDeviceIndex(eq(faceId), eq(0), anyInt(), anyString());
    }

    @Test
    @DisplayName("当source不存在时应该返回null")
    void shouldReturnNullWhenSourceNotFound() throws Exception {
        // Given
        Long faceId = 999L;
        Integer deviceIndex = 0;

        when(sourceMapper.getSourceByFaceAndDeviceIndex(anyLong(), anyInt(), anyInt(), anyString()))
                .thenReturn(null);

        DataSourceContext context = DataSourceContext.builder()
                .faceId(faceId)
                .build();

        JsonNode sourceFilter = objectMapper.readTree("{\"type\": 2, \"deviceIndex\": 0}");

        // When
        String result = strategy.resolve(sourceFilter, "LATEST", context);

        // Then
        assertNull(result);
    }

    @Test
    @DisplayName("当未指定sortStrategy时应该默认使用LATEST")
    void shouldDefaultToLatestSortStrategy() throws Exception {
        // Given
        Long faceId = 123L;

        SourceEntity source = new SourceEntity();
        source.setType(2);
        source.setUrl("https://oss.example.com/img.jpg");

        when(sourceMapper.getSourceByFaceAndDeviceIndex(anyLong(), anyInt(), anyInt(), eq("LATEST")))
                .thenReturn(source);

        DataSourceContext context = DataSourceContext.builder()
                .faceId(faceId)
                .build();

        JsonNode sourceFilter = objectMapper.readTree("{\"deviceIndex\": 0}");

        // When
        strategy.resolve(sourceFilter, null, context);

        // Then
        verify(sourceMapper, times(1)).getSourceByFaceAndDeviceIndex(anyLong(), anyInt(), anyInt(), eq("LATEST"));
    }

    @Test
    @DisplayName("当sourceMapper抛出异常时应该返回null")
    void shouldReturnNullWhenSourceMapperThrowsException() throws Exception {
        // Given
        Long faceId = 123L;

        when(sourceMapper.getSourceByFaceAndDeviceIndex(anyLong(), anyInt(), anyInt(), anyString()))
                .thenThrow(new RuntimeException("Database error"));

        DataSourceContext context = DataSourceContext.builder()
                .faceId(faceId)
                .build();

        JsonNode sourceFilter = objectMapper.readTree("{\"deviceIndex\": 0}");

        // When
        String result = strategy.resolve(sourceFilter, "LATEST", context);

        // Then
        assertNull(result);
    }
}
