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.mapper.VideoMapper;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
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 static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.*;

/**
 * DeleteOldRelationsStage 单元测试
 */
@ExtendWith(MockitoExtension.class)
class DeleteOldRelationsStageTest {

    @Mock
    private SourceMapper sourceMapper;

    @Mock
    private VideoMapper videoMapper;

    @Mock
    private MemberRelationRepository memberRelationRepository;

    @Mock
    private FaceStatusManager faceStatusManager;

    @InjectMocks
    private DeleteOldRelationsStage stage;

    private FaceMatchingContext context;
    private FaceEntity face;

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

        face = new FaceEntity();
        face.setId(1L);
        face.setMemberId(100L);
        face.setScenicId(10L);

        context.setFace(face);
    }

    @Test
    void testExecute_Success() {
        // Given - mock方法默认不做任何事,无需doNothing()

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

        // Then
        assertTrue(result.isSuccess());
        assertTrue(result.getMessage().contains("旧关系数据已删除"));
        verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 1L);
        verify(videoMapper, times(1)).deleteNotBuyFaceRelations(100L, 1L);
        verify(memberRelationRepository, times(1)).clearSCacheByFace(1L);
        verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
    }

    @Test
    void testExecute_SourceMapperFailed_Degraded() {
        // Given
        doThrow(new RuntimeException("Database error"))
                .when(sourceMapper).deleteNotBuyFaceRelation(100L, 1L);

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

        // Then
        assertTrue(result.isDegraded()); // 降级处理,不影响主流程
        assertTrue(result.getMessage().contains("删除旧关系数据失败"));
        verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 1L);
        verify(videoMapper, never()).deleteNotBuyFaceRelations(anyLong(), anyLong());
        verify(memberRelationRepository, never()).clearSCacheByFace(anyLong());
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_VideoMapperFailed_Degraded() {
        // Given - sourceMapper正常执行(无需doNothing)
        doThrow(new RuntimeException("Delete video error"))
                .when(videoMapper).deleteNotBuyFaceRelations(100L, 1L);

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

        // Then
        assertTrue(result.isDegraded());
        verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 1L);
        verify(videoMapper, times(1)).deleteNotBuyFaceRelations(100L, 1L);
        verify(memberRelationRepository, never()).clearSCacheByFace(anyLong());
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_CacheClearFailed_Degraded() {
        // Given - sourceMapper和videoMapper正常执行
        doThrow(new RuntimeException("Cache error"))
                .when(memberRelationRepository).clearSCacheByFace(1L);

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

        // Then
        assertTrue(result.isDegraded());
        verify(memberRelationRepository, times(1)).clearSCacheByFace(1L);
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_DifferentMemberId() {
        // Given: 不同的memberId
        face.setMemberId(999L);

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

        // Then
        assertTrue(result.isSuccess());
        verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(999L, 1L);
        verify(videoMapper, times(1)).deleteNotBuyFaceRelations(999L, 1L);
        verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
    }

    @Test
    void testExecute_DifferentFaceId() {
        // Given: 不同的faceId
        context = FaceMatchingContext.forAutoMatching(888L, true);
        face.setId(888L);
        context.setFace(face);

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

        // Then
        assertTrue(result.isSuccess());
        verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 888L);
        verify(videoMapper, times(1)).deleteNotBuyFaceRelations(100L, 888L);
        verify(memberRelationRepository, times(1)).clearSCacheByFace(888L);
        verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(888L);
    }

    @Test
    void testExecute_NullPointerException_Degraded() {
        // Given
        doThrow(new NullPointerException("Null member"))
                .when(sourceMapper).deleteNotBuyFaceRelation(100L, 1L);

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

        // Then
        assertTrue(result.isDegraded());
        assertTrue(result.getMessage().contains("删除旧关系数据失败"));
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }

    @Test
    void testExecute_PartialSuccess_Degraded() {
        // Given: sourceMapper成功,但videoMapper失败
        doThrow(new RuntimeException("Video deletion failed"))
                .when(videoMapper).deleteNotBuyFaceRelations(100L, 1L);

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

        // Then
        assertTrue(result.isDegraded());
        // source删除成功,但video删除失败
        verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 1L);
        verify(videoMapper, times(1)).deleteNotBuyFaceRelations(100L, 1L);
        verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
    }
}
