package com.ruoyi.web.modules.video.service;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.Collections;
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 com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.industryservice.domain.vo.YakAssetSyncResultVo;
import com.ruoyi.web.modules.video.domain.dto.OpenCameraDto;
import com.ruoyi.web.modules.video.support.LivestockMonitorSyncRules;
import com.ruoyi.web.modules.video.support.ThirdPartyCameraClient;

@ExtendWith(MockitoExtension.class)
@DisplayName("畜牧监控第三方同步")
class LivestockMonitorSyncServiceTest
{
    @Mock
    private ThirdPartyCameraClient thirdPartyCameraClient;

    @Mock
    private LivestockMonitorSyncTxService livestockMonitorSyncTxService;

    @InjectMocks
    private LivestockMonitorSyncService livestockMonitorSyncService;

    @Test
    @DisplayName("第三方未启用")
    void syncDisabled()
    {
        when(thirdPartyCameraClient.fetchAllCameras()).thenThrow(new ServiceException("第三方监控同步未启用"));
        assertThrows(ServiceException.class, () -> livestockMonitorSyncService.syncFromThirdParty("tester"));
    }

    @Test
    @DisplayName("空列表同步")
    void syncEmpty()
    {
        when(thirdPartyCameraClient.fetchAllCameras()).thenReturn(Collections.emptyList());
        YakAssetSyncResultVo result = livestockMonitorSyncService.syncFromThirdParty("tester");
        assertNotNull(result.getSyncTime());
        assertEquals(0, result.getInsertCount());
    }

    @Test
    @DisplayName("新增与更新统计")
    void syncInsertAndUpdate()
    {
        OpenCameraDto camera1 = new OpenCameraDto();
        camera1.setCameraId(1L);
        camera1.setDeviceName("监控1");
        camera1.setVideoSource("wvp");
        OpenCameraDto camera2 = new OpenCameraDto();
        camera2.setCameraId(2L);
        camera2.setDeviceName("监控2");
        camera2.setVideoSource("ys7");
        when(thirdPartyCameraClient.fetchAllCameras()).thenReturn(Arrays.asList(camera1, camera2));
        when(livestockMonitorSyncTxService.persistCamera(any(), any(), any())).thenReturn(true, false);
        YakAssetSyncResultVo result = livestockMonitorSyncService.syncFromThirdParty("tester");
        assertEquals(1, result.getInsertCount());
        assertEquals(1, result.getUpdateCount());
        assertEquals(0, result.getFailCount());
    }

    @Test
    @DisplayName("单条落库失败计入失败数")
    void syncPersistFail()
    {
        OpenCameraDto camera = new OpenCameraDto();
        camera.setCameraId(1L);
        camera.setDeviceName("监控1");
        camera.setVideoSource("wvp");
        when(thirdPartyCameraClient.fetchAllCameras()).thenReturn(Collections.singletonList(camera));
        when(livestockMonitorSyncTxService.persistCamera(any(), any(), any()))
                .thenThrow(new ServiceException("视频来源不能为空"));
        YakAssetSyncResultVo result = livestockMonitorSyncService.syncFromThirdParty("tester");
        assertEquals(1, result.getFailCount());
        assertEquals(1, result.getFailMessages().size());
    }

    @Test
    @DisplayName("并发同步拒绝")
    void syncInProgress() throws Exception
    {
        OpenCameraDto camera = new OpenCameraDto();
        camera.setCameraId(1L);
        camera.setDeviceName("监控1");
        camera.setVideoSource("wvp");
        when(thirdPartyCameraClient.fetchAllCameras()).thenReturn(Collections.singletonList(camera));
        when(livestockMonitorSyncTxService.persistCamera(any(), any(), any())).thenAnswer(invocation -> {
            Thread.sleep(200);
            return true;
        });
        Thread t1 = new Thread(() -> livestockMonitorSyncService.syncFromThirdParty("tester"));
        t1.start();
        Thread.sleep(50);
        ServiceException ex = assertThrows(ServiceException.class, () -> livestockMonitorSyncService.syncFromThirdParty("tester2"));
        assertEquals(LivestockMonitorSyncRules.MSG_SYNC_IN_PROGRESS, ex.getMessage());
        t1.join();
    }
}
