package com.ycwl.basic.puzzle.service.impl;

import com.ycwl.basic.biz.FaceStatusManager;
import com.ycwl.basic.puzzle.dto.PuzzleGenerateRequest;
import com.ycwl.basic.puzzle.dto.PuzzleGenerateResponse;
import com.ycwl.basic.puzzle.edge.task.PuzzleEdgeRenderTaskService;
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.entity.PuzzleGenerationRecordEntity;
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
import com.ycwl.basic.puzzle.exception.DuplicateImageException;
import com.ycwl.basic.puzzle.fill.FillResult;
import com.ycwl.basic.puzzle.fill.PuzzleElementFillEngine;
import com.ycwl.basic.puzzle.mapper.PuzzleGenerationRecordMapper;
import com.ycwl.basic.puzzle.repository.PuzzleRepository;
import com.ycwl.basic.puzzle.util.PuzzleDuplicationDetector;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.pc.processor.PuzzleRelationProcessor;
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.HashMap;
import java.util.List;
import java.util.Map;

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

/**
 * PuzzleGenerateServiceImpl 去重功能集成测试
 *
 * @author Claude
 * @since 2025-01-21
 */
@ExtendWith(MockitoExtension.class)
class PuzzleGenerateServiceDeduplicationTest {

    @Mock
    private PuzzleRepository puzzleRepository;

    @Mock
    private PuzzleGenerationRecordMapper recordMapper;

    @Mock
    private PuzzleElementFillEngine fillEngine;

    @Mock
    private ScenicRepository scenicRepository;

    @Mock
    private PuzzleDuplicationDetector duplicationDetector;

    @Mock
    private PuzzleEdgeRenderTaskService puzzleEdgeRenderTaskService;

    @Mock
    private FaceStatusManager faceStatusManager;

    @Mock
    private PuzzleRelationProcessor puzzleRelationProcessor;

    @InjectMocks
    private PuzzleGenerateServiceImpl service;

    @BeforeEach
    void setUp() {
        // MockitoExtension 会自动初始化 mocks
    }

    /**
     * 测试场景1: 首次生成 - 应该正常渲染并保存
     */
    @Test
    void testGenerate_首次生成() throws Exception {
        // 准备请求
        PuzzleGenerateRequest request = createBasicRequest();

        // Mock模板
        PuzzleTemplateEntity template = createMockTemplate();
        when(puzzleRepository.getTemplateByCode("test_template")).thenReturn(template);

        // Mock元素
        List<PuzzleElementEntity> elements = createMockElements();
        when(puzzleRepository.getElementsByTemplateId(1L)).thenReturn(elements);

        // Mock 素材版本缓存检查
        when(faceStatusManager.isPuzzleSourceChanged(anyLong(), anyLong(), anyInt())).thenReturn(true);

        // Mock自动填充
        FillResult fillResult = FillResult.noMatch();
        when(fillEngine.execute(anyLong(), anyLong(), anyLong())).thenReturn(fillResult);

        // Mock去重检测 - 不重复
        when(duplicationDetector.findDuplicateRecord(anyLong(), anyString(), anyLong())).thenReturn(null);
        when(duplicationDetector.calculateContentHash(anyMap())).thenReturn("hash123");

        // Mock插入记录
        doAnswer(invocation -> {
            PuzzleGenerationRecordEntity record = invocation.getArgument(0);
            record.setId(100L);
            return 1;
        }).when(recordMapper).insert(any());

        // Mock 边缘渲染任务
        when(puzzleEdgeRenderTaskService.createRenderTask(any(), any(), any(), any(), any(), any()))
                .thenReturn(100L);
        when(puzzleEdgeRenderTaskService.waitForTask(anyLong(), anyLong()))
                .thenReturn(PuzzleEdgeRenderTaskService.TaskWaitResult.success("https://example.com/final.png"));

        // Mock 获取更新后的记录
        PuzzleGenerationRecordEntity updatedRecord = new PuzzleGenerationRecordEntity();
        updatedRecord.setId(100L);
        updatedRecord.setResultImageUrl("https://example.com/final.png");
        updatedRecord.setResultFileSize(12345L);
        updatedRecord.setResultWidth(750);
        updatedRecord.setResultHeight(1334);
        when(recordMapper.getById(100L)).thenReturn(updatedRecord);

        // 执行
        PuzzleGenerateResponse response = service.generate(request);

        // 验证
        assertNotNull(response);
        verify(recordMapper, times(1)).insert(any()); // 插入了一条记录
    }

    /**
     * 测试场景2: 相同内容再次生成 - 应该复用历史记录
     */
    @Test
    void testGenerate_复用历史记录() throws Exception {
        // 准备请求
        PuzzleGenerateRequest request = createBasicRequest();

        // Mock模板
        PuzzleTemplateEntity template = createMockTemplate();
        when(puzzleRepository.getTemplateByCode("test_template")).thenReturn(template);

        // Mock元素
        List<PuzzleElementEntity> elements = createMockElements();
        when(puzzleRepository.getElementsByTemplateId(1L)).thenReturn(elements);

        // Mock 素材版本缓存检查
        when(faceStatusManager.isPuzzleSourceChanged(anyLong(), anyLong(), anyInt())).thenReturn(true);

        // Mock自动填充
        FillResult fillResult = FillResult.noMatch();
        when(fillEngine.execute(anyLong(), anyLong(), anyLong())).thenReturn(fillResult);

        // Mock去重查询 - 找到历史记录
        PuzzleGenerationRecordEntity historicalRecord = createHistoricalRecord();
        when(duplicationDetector.calculateContentHash(anyMap())).thenReturn("hash123");
        when(duplicationDetector.findDuplicateRecord(anyLong(), anyString(), anyLong())).thenReturn(historicalRecord);

        // 执行
        PuzzleGenerateResponse response = service.generate(request);

        // 验证
        assertNotNull(response);
        assertTrue(response.getIsDuplicate()); // 标记为复用
        assertEquals(999L, response.getOriginalRecordId()); // 原始记录ID(复用时指向自己)
        assertEquals(999L, response.getRecordId()); // recordId也是历史记录的ID
        assertEquals("https://example.com/old-image.jpg", response.getImageUrl()); // 复用的URL
        verify(puzzleEdgeRenderTaskService, never()).createRenderTask(any(), any(), any(), any(), any(), any()); // 没有进行渲染
        verify(recordMapper, never()).insert(any()); // 没有插入新记录
    }

    /**
     * 测试场景3: 所有图片相同 - 应该抛出异常
     */
    @Test
    void testGenerate_所有图片相同抛出异常() {
        // 准备请求 - 所有图片URL相同
        PuzzleGenerateRequest request = new PuzzleGenerateRequest();
        request.setTemplateCode("test_template");
        request.setFaceId(1000L);
        request.setScenicId(1L);

        Map<String, String> dynamicData = new HashMap<>();
        dynamicData.put("image1", "https://example.com/same.jpg");
        dynamicData.put("image2", "https://example.com/same.jpg");
        request.setDynamicData(dynamicData);

        // Mock模板
        PuzzleTemplateEntity template = createMockTemplate();
        when(puzzleRepository.getTemplateByCode("test_template")).thenReturn(template);

        // Mock元素 - 两个图片元素
        List<PuzzleElementEntity> elements = new ArrayList<>();
        elements.add(createImageElement(1L, "image1"));
        elements.add(createImageElement(2L, "image2"));
        when(puzzleRepository.getElementsByTemplateId(1L)).thenReturn(elements);

        // Mock 素材版本缓存检查
        when(faceStatusManager.isPuzzleSourceChanged(anyLong(), anyLong(), anyInt())).thenReturn(true);

        // Mock自动填充
        FillResult fillResult = FillResult.noMatch();
        when(fillEngine.execute(anyLong(), anyLong(), anyLong())).thenReturn(fillResult);

        // Mock 去重检测 - 抛出重复图片异常
        doThrow(new DuplicateImageException("https://example.com/same.jpg", 2))
                .when(duplicationDetector).detectDuplicateImages(anyMap(), anyList());

        // 执行并验证 - 应该抛出DuplicateImageException
        assertThrows(DuplicateImageException.class, () -> service.generate(request));

        // 验证没有进行渲染和保存
        verify(puzzleEdgeRenderTaskService, never()).createRenderTask(any(), any(), any(), any(), any(), any());
        verify(recordMapper, never()).insert(any());
    }

    /**
     * 测试场景4: 不同参数生成不同图片
     */
    @Test
    void testGenerate_不同内容生成不同图片() throws Exception {
        // 第一次请求
        PuzzleGenerateRequest request1 = createBasicRequest();
        request1.getDynamicData().put("userName", "张三");

        // 第二次请求 - 不同的用户名
        PuzzleGenerateRequest request2 = createBasicRequest();
        request2.getDynamicData().put("userName", "李四");

        // Mock基础数据
        PuzzleTemplateEntity template = createMockTemplate();
        when(puzzleRepository.getTemplateByCode("test_template")).thenReturn(template);

        List<PuzzleElementEntity> elements = createMockElements();
        when(puzzleRepository.getElementsByTemplateId(1L)).thenReturn(elements);

        // Mock 素材版本缓存检查
        when(faceStatusManager.isPuzzleSourceChanged(anyLong(), anyLong(), anyInt())).thenReturn(true);

        FillResult fillResult = FillResult.noMatch();
        when(fillEngine.execute(anyLong(), anyLong(), anyLong())).thenReturn(fillResult);

        // Mock去重查询 - 两次都未找到
        when(duplicationDetector.findDuplicateRecord(anyLong(), anyString(), anyLong())).thenReturn(null);
        when(duplicationDetector.calculateContentHash(anyMap())).thenReturn("hash1", "hash2");

        doAnswer(invocation -> {
            PuzzleGenerationRecordEntity record = invocation.getArgument(0);
            record.setId(Math.abs(record.hashCode()) % 1000L);
            return 1;
        }).when(recordMapper).insert(any());

        // Mock 边缘渲染任务
        when(puzzleEdgeRenderTaskService.createRenderTask(any(), any(), any(), any(), any(), any()))
                .thenReturn(100L, 101L);
        when(puzzleEdgeRenderTaskService.waitForTask(anyLong(), anyLong()))
                .thenReturn(PuzzleEdgeRenderTaskService.TaskWaitResult.success("https://example.com/img1.png"))
                .thenReturn(PuzzleEdgeRenderTaskService.TaskWaitResult.success("https://example.com/img2.png"));

        // Mock 获取更新后的记录
        PuzzleGenerationRecordEntity record1 = new PuzzleGenerationRecordEntity();
        record1.setResultImageUrl("https://example.com/img1.png");
        record1.setResultFileSize(12345L);
        record1.setResultWidth(750);
        record1.setResultHeight(1334);

        PuzzleGenerationRecordEntity record2 = new PuzzleGenerationRecordEntity();
        record2.setResultImageUrl("https://example.com/img2.png");
        record2.setResultFileSize(12346L);
        record2.setResultWidth(750);
        record2.setResultHeight(1334);

        when(recordMapper.getById(anyLong())).thenReturn(record1, record2);

        // 执行两次生成
        PuzzleGenerateResponse response1 = service.generate(request1);
        PuzzleGenerateResponse response2 = service.generate(request2);

        // 验证: 两次都是新生成
        assertNotNull(response1);
        assertNotNull(response2);
        verify(puzzleEdgeRenderTaskService, times(2)).createRenderTask(any(), any(), any(), any(), any(), any()); // 渲染了两次
    }

    // ===== 辅助方法 =====

    private PuzzleGenerateRequest createBasicRequest() {
        PuzzleGenerateRequest request = new PuzzleGenerateRequest();
        request.setTemplateCode("test_template");
        request.setUserId(100L);
        request.setFaceId(1000L);
        request.setScenicId(1L);
        request.setBusinessType("order");

        Map<String, String> dynamicData = new HashMap<>();
        dynamicData.put("image1", "https://example.com/img1.jpg");
        dynamicData.put("image2", "https://example.com/img2.jpg");
        request.setDynamicData(dynamicData);

        return request;
    }

    private PuzzleTemplateEntity createMockTemplate() {
        PuzzleTemplateEntity template = new PuzzleTemplateEntity();
        template.setId(1L);
        template.setCode("test_template");
        template.setName("测试模板");
        template.setStatus(1);
        template.setScenicId(1L);
        template.setCanvasWidth(750);
        template.setCanvasHeight(1334);
        template.setBackgroundType(0);
        template.setBackgroundColor("#FFFFFF");
        return template;
    }

    private List<PuzzleElementEntity> createMockElements() {
        List<PuzzleElementEntity> elements = new ArrayList<>();
        elements.add(createImageElement(1L, "image1"));
        elements.add(createImageElement(2L, "image2"));
        return elements;
    }

    private PuzzleElementEntity createImageElement(Long id, String elementKey) {
        PuzzleElementEntity element = new PuzzleElementEntity();
        element.setId(id);
        element.setElementKey(elementKey);
        element.setElementType("IMAGE"); // IMAGE类型
        element.setZIndex(10);
        return element;
    }

    private PuzzleGenerationRecordEntity createHistoricalRecord() {
        PuzzleGenerationRecordEntity record = new PuzzleGenerationRecordEntity();
        record.setId(999L);
        record.setTemplateId(1L);
        record.setTemplateCode("test_template");
        record.setResultImageUrl("https://example.com/old-image.jpg");
        record.setResultFileSize(123456L);
        record.setResultWidth(750);
        record.setResultHeight(1334);
        record.setStatus(1);
        return record;
    }
}
