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

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Collections;
import java.util.Date;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.web.modules.industryservice.domain.vo.IotDataIncrementalSyncResultVo;
import com.ruoyi.web.modules.industryservice.domain.vo.YakAssetSyncResultVo;
import com.ruoyi.web.modules.industryservice.mapper.BizEnvMonitoringRecordMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizYakCollarLocationMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizYakEarTagRecordMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizYakWeighingRecordMapper;
import com.ruoyi.web.modules.industryservice.support.IotSyncSupport.SyncQuery;

@ExtendWith(MockitoExtension.class)
@DisplayName("IotDataIncrementalSyncService")
class IotDataIncrementalSyncServiceTest
{
    @Mock
    private YakWeighingSyncService yakWeighingSyncService;

    @Mock
    private YakEarTagSyncService yakEarTagSyncService;

    @Mock
    private YakCollarLocationSyncService yakCollarLocationSyncService;

    @Mock
    private EnvMonitoringSyncService envMonitoringSyncService;

    @Mock
    private BizYakWeighingRecordMapper weighingRecordMapper;

    @Mock
    private BizYakEarTagRecordMapper earTagRecordMapper;

    @Mock
    private BizYakCollarLocationMapper collarLocationMapper;

    @Mock
    private BizEnvMonitoringRecordMapper envMonitoringRecordMapper;

    @Mock
    private ISysConfigService configService;

    @InjectMocks
    private IotDataIncrementalSyncService service;

    @Test
    @DisplayName("有本地数据时按增量同步")
    void syncIncremental_inOrder()
    {
        YakAssetSyncResultVo empty = new YakAssetSyncResultVo();
        when(configService.selectConfigByKey("third_party.iot.last_sync_time")).thenReturn("");
        when(weighingRecordMapper.countRecords()).thenReturn(10L);
        when(earTagRecordMapper.countRecords()).thenReturn(5L);
        when(collarLocationMapper.countRecords()).thenReturn(20L);
        when(envMonitoringRecordMapper.countRecords()).thenReturn(30L);
        when(weighingRecordMapper.selectMaxWeighingTime()).thenReturn(new Date(1_000L));
        when(earTagRecordMapper.selectMaxReportTime()).thenReturn(new Date(1_500L));
        when(collarLocationMapper.selectMaxReportTime()).thenReturn(new Date(2_000L));
        when(envMonitoringRecordMapper.selectMaxMonitoringTime()).thenReturn(new Date(3_000L));
        when(yakWeighingSyncService.syncIncremental(any(SyncQuery.class))).thenReturn(empty);
        when(yakEarTagSyncService.syncIncremental(any(SyncQuery.class))).thenReturn(empty);
        when(yakCollarLocationSyncService.syncIncremental(any(SyncQuery.class))).thenReturn(empty);
        when(envMonitoringSyncService.syncIncremental(any(SyncQuery.class))).thenReturn(empty);
        when(configService.selectConfigList(any())).thenReturn(Collections.emptyList());

        IotDataIncrementalSyncResultVo result = service.syncIncremental();

        assertNotNull(result.getSyncTime());
        verify(yakWeighingSyncService).syncIncremental(any(SyncQuery.class));
        verify(yakEarTagSyncService).syncIncremental(any(SyncQuery.class));
        verify(yakCollarLocationSyncService).syncIncremental(any(SyncQuery.class));
        verify(envMonitoringSyncService).syncIncremental(any(SyncQuery.class));
        verify(configService).insertConfig(any());
    }

    @Test
    @DisplayName("表清空后全量回补，不使用 config 水印")
    void syncIncremental_afterTableCleared()
    {
        YakAssetSyncResultVo empty = new YakAssetSyncResultVo();
        when(configService.selectConfigByKey("third_party.iot.last_sync_time"))
                .thenReturn("2026-05-20 10:00:00");
        when(weighingRecordMapper.countRecords()).thenReturn(0L);
        when(earTagRecordMapper.countRecords()).thenReturn(0L);
        when(collarLocationMapper.countRecords()).thenReturn(0L);
        when(envMonitoringRecordMapper.countRecords()).thenReturn(0L);
        when(yakWeighingSyncService.syncIncremental(any(SyncQuery.class))).thenReturn(empty);
        when(yakEarTagSyncService.syncIncremental(any(SyncQuery.class))).thenReturn(empty);
        when(yakCollarLocationSyncService.syncIncremental(any(SyncQuery.class))).thenReturn(empty);
        when(envMonitoringSyncService.syncIncremental(any(SyncQuery.class))).thenReturn(empty);
        when(configService.selectConfigList(any())).thenReturn(Collections.emptyList());

        service.syncIncremental();

        ArgumentCaptor<SyncQuery> weighingCaptor = ArgumentCaptor.forClass(SyncQuery.class);
        verify(yakWeighingSyncService).syncIncremental(weighingCaptor.capture());
        assertTrue(weighingCaptor.getValue().isFullSync());
        verify(yakEarTagSyncService).syncIncremental(any(SyncQuery.class));
        verify(yakCollarLocationSyncService).syncIncremental(any(SyncQuery.class));
        verify(envMonitoringSyncService).syncIncremental(any(SyncQuery.class));
    }
}
