package com.ycwl.basic.face.pipeline.stages;

import com.ycwl.basic.biz.FaceStatusManager;
import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.pipeline.core.StageResult;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
import com.ycwl.basic.repository.MemberRelationRepository;
import org.junit.jupiter.api.BeforeEach;
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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

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

/**
 * PersistRelationsStage 单元测试
 */
@ExtendWith(MockitoExtension.class)
class PersistRelationsStageTest {

    @Mock
    private SourceMapper sourceMapper;

    @Mock
    private MemberRelationRepository memberRelationRepository;

    @Mock
    private FaceStatusManager faceStatusManager;

    @InjectMocks
    private PersistRelationsStage stage;

    private FaceMatchingContext context;

    @BeforeEach
    void setUp() {
        context = FaceMatchingContext.forAutoMatching(1L, true);
    }

    @Test
    void testExecute_Success() {
        // Given
        List<MemberSourceEntity> memberSourceList = createMemberSourceList(3);
        context.setMemberSourceList(memberSourceList);

        List<MemberSourceEntity> afterExistingFilter = createMemberSourceList(2);
        List<MemberSourceEntity> afterValidFilter = createMemberSourceList(2);

        when(sourceMapper.filterExistingRelations(memberSourceList))
                .thenReturn(afterExistingFilter);
        when(sourceMapper.filterValidSourceRelations(afterExistingFilter))
                .thenReturn(afterValidFilter);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSuccess());
        assertTrue(result.getMessage().contains("持久化了2条关联关系"));
        verify(sourceMapper, times(1)).filterExistingRelations(memberSourceList);
        verify(sourceMapper, times(1)).filterValidSourceRelations(afterExistingFilter);
        verify(sourceMapper, times(1)).addRelations(afterValidFilter);
        verify(memberRelationRepository, times(1)).clearSCacheByFace(1L);
        verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
    }

    @Test
    void testExecute_MemberSourceListNull_Skipped() {
        // Given
        context.setMemberSourceList(null);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSkipped());
        assertTrue(result.getMessage().contains("memberSourceList为空"));
        verify(sourceMapper, never()).filterExistingRelations(anyList());
        verify(sourceMapper, never()).addRelations(anyList());
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_MemberSourceListEmpty_Skipped() {
        // Given
        context.setMemberSourceList(new ArrayList<>());

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSkipped());
        assertTrue(result.getMessage().contains("memberSourceList为空"));
        verify(sourceMapper, never()).filterExistingRelations(anyList());
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_AllFilteredByExisting_Skipped() {
        // Given: 所有关系都已存在
        List<MemberSourceEntity> memberSourceList = createMemberSourceList(5);
        context.setMemberSourceList(memberSourceList);

        when(sourceMapper.filterExistingRelations(memberSourceList))
                .thenReturn(new ArrayList<>()); // 全部被过滤

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSkipped());
        assertTrue(result.getMessage().contains("没有有效的关联关系可创建"));
        verify(sourceMapper, times(1)).filterExistingRelations(memberSourceList);
        verify(sourceMapper, never()).addRelations(anyList());
        verify(memberRelationRepository, never()).clearSCacheByFace(anyLong());
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_AllFilteredByInvalid_Skipped() {
        // Given: 过滤掉已存在的后,剩余的都是无效引用
        List<MemberSourceEntity> memberSourceList = createMemberSourceList(5);
        context.setMemberSourceList(memberSourceList);

        List<MemberSourceEntity> afterExistingFilter = createMemberSourceList(3);

        when(sourceMapper.filterExistingRelations(memberSourceList))
                .thenReturn(afterExistingFilter);
        when(sourceMapper.filterValidSourceRelations(afterExistingFilter))
                .thenReturn(new ArrayList<>()); // 全部无效

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSkipped());
        assertTrue(result.getMessage().contains("没有有效的关联关系可创建"));
        verify(sourceMapper, times(1)).filterValidSourceRelations(afterExistingFilter);
        verify(sourceMapper, never()).addRelations(anyList());
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_PartialFiltered() {
        // Given: 部分被过滤,部分有效
        List<MemberSourceEntity> memberSourceList = createMemberSourceList(10);
        context.setMemberSourceList(memberSourceList);

        List<MemberSourceEntity> afterExistingFilter = createMemberSourceList(7);
        List<MemberSourceEntity> afterValidFilter = createMemberSourceList(5);

        when(sourceMapper.filterExistingRelations(memberSourceList))
                .thenReturn(afterExistingFilter);
        when(sourceMapper.filterValidSourceRelations(afterExistingFilter))
                .thenReturn(afterValidFilter);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSuccess());
        assertTrue(result.getMessage().contains("持久化了5条关联关系"));
        verify(sourceMapper, times(1)).addRelations(afterValidFilter);
        verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
    }

    @Test
    void testExecute_FilterExistingThrowsException_Failed() {
        // Given
        List<MemberSourceEntity> memberSourceList = createMemberSourceList(3);
        context.setMemberSourceList(memberSourceList);

        when(sourceMapper.filterExistingRelations(memberSourceList))
                .thenThrow(new RuntimeException("Database error"));

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isFailed());
        assertTrue(result.getMessage().contains("保存关联关系失败"));
        assertNotNull(result.getException());
        verify(sourceMapper, never()).addRelations(anyList());
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_AddRelationsThrowsException_Failed() {
        // Given
        List<MemberSourceEntity> memberSourceList = createMemberSourceList(3);
        context.setMemberSourceList(memberSourceList);

        List<MemberSourceEntity> afterExistingFilter = createMemberSourceList(2);
        List<MemberSourceEntity> afterValidFilter = createMemberSourceList(2);

        when(sourceMapper.filterExistingRelations(memberSourceList))
                .thenReturn(afterExistingFilter);
        when(sourceMapper.filterValidSourceRelations(afterExistingFilter))
                .thenReturn(afterValidFilter);
        doThrow(new RuntimeException("Insert error")).when(sourceMapper).addRelations(afterValidFilter);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isFailed());
        verify(memberRelationRepository, never()).clearSCacheByFace(anyLong()); // 失败时不清缓存
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_CacheClearFailed() {
        // Given
        List<MemberSourceEntity> memberSourceList = createMemberSourceList(3);
        context.setMemberSourceList(memberSourceList);

        List<MemberSourceEntity> afterExistingFilter = createMemberSourceList(2);
        List<MemberSourceEntity> afterValidFilter = createMemberSourceList(2);

        when(sourceMapper.filterExistingRelations(memberSourceList))
                .thenReturn(afterExistingFilter);
        when(sourceMapper.filterValidSourceRelations(afterExistingFilter))
                .thenReturn(afterValidFilter);
        doThrow(new RuntimeException("Cache clear error"))
                .when(memberRelationRepository).clearSCacheByFace(1L);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isFailed()); // 缓存清理失败导致整体失败
        verify(sourceMapper, times(1)).addRelations(afterValidFilter); // 但关系已保存
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_SingleRelation() {
        // Given: 只有1条关系
        List<MemberSourceEntity> memberSourceList = createMemberSourceList(1);
        context.setMemberSourceList(memberSourceList);

        when(sourceMapper.filterExistingRelations(memberSourceList))
                .thenReturn(memberSourceList);
        when(sourceMapper.filterValidSourceRelations(memberSourceList))
                .thenReturn(memberSourceList);

        // When
        StageResult<FaceMatchingContext> result = stage.execute(context);

        // Then
        assertTrue(result.isSuccess());
        assertTrue(result.getMessage().contains("持久化了1条关联关系"));
        verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
    }

    private List<MemberSourceEntity> createMemberSourceList(int count) {
        List<MemberSourceEntity> list = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            MemberSourceEntity entity = new MemberSourceEntity();
            entity.setMemberId(100L);
            entity.setSourceId((long) (i + 1));
            list.add(entity);
        }
        return list;
    }
}
