package com.ycwl.basic.puzzle.util;

import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.entity.PuzzleGenerationRecordEntity;
import com.ycwl.basic.puzzle.exception.DuplicateImageException;
import com.ycwl.basic.puzzle.mapper.PuzzleGenerationRecordMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

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.*;

/**
 * PuzzleDuplicationDetector 单元测试
 *
 * @author Claude
 * @since 2025-01-21
 */
class PuzzleDuplicationDetectorTest {

    @Mock
    private PuzzleGenerationRecordMapper recordMapper;

    @InjectMocks
    private PuzzleDuplicationDetector detector;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void testCalculateContentHash_基本功能() {
        // 准备数据
        Map<String, String> data = new HashMap<>();
        data.put("userName", "张三");
        data.put("userAvatar", "https://example.com/avatar.jpg");

        // 执行
        String hash = detector.calculateContentHash(data);

        // 验证
        assertNotNull(hash);
        assertEquals(64, hash.length()); // SHA256产生64位16进制字符串
    }

    @Test
    void testCalculateContentHash_相同内容产生相同哈希() {
        // 准备数据
        Map<String, String> data1 = new HashMap<>();
        data1.put("userName", "张三");
        data1.put("userAvatar", "https://example.com/avatar.jpg");

        Map<String, String> data2 = new HashMap<>();
        data2.put("userAvatar", "https://example.com/avatar.jpg");
        data2.put("userName", "张三");

        // 执行
        String hash1 = detector.calculateContentHash(data1);
        String hash2 = detector.calculateContentHash(data2);

        // 验证: 不同顺序的key应该产生相同哈希
        assertEquals(hash1, hash2);
    }

    @Test
    void testCalculateContentHash_不同内容产生不同哈希() {
        // 准备数据
        Map<String, String> data1 = new HashMap<>();
        data1.put("userName", "张三");

        Map<String, String> data2 = new HashMap<>();
        data2.put("userName", "李四");

        // 执行
        String hash1 = detector.calculateContentHash(data1);
        String hash2 = detector.calculateContentHash(data2);

        // 验证
        assertNotEquals(hash1, hash2);
    }

    @Test
    void testCalculateContentHash_空数据() {
        Map<String, String> emptyData = new HashMap<>();

        String hash = detector.calculateContentHash(emptyData);

        assertNotNull(hash);
        assertEquals("", hash);
    }

    @Test
    void testDetectDuplicateImages_所有图片相同抛出异常() {
        // 准备数据
        Map<String, String> data = new HashMap<>();
        data.put("image1", "https://example.com/same.jpg");
        data.put("image2", "https://example.com/same.jpg");
        data.put("image3", "https://example.com/same.jpg");

        List<PuzzleElementEntity> elements = new ArrayList<>();
        elements.add(createImageElement(1L, "image1"));
        elements.add(createImageElement(2L, "image2"));
        elements.add(createImageElement(3L, "image3"));

        // 执行并验证
        DuplicateImageException exception = assertThrows(
                DuplicateImageException.class,
                () -> detector.detectDuplicateImages(data, elements)
        );

        assertTrue(exception.getMessage().contains("https://example.com/same.jpg"));
        assertEquals(3, exception.getElementCount());
    }

    @Test
    void testDetectDuplicateImages_不同图片不抛异常() {
        // 准备数据
        Map<String, String> data = new HashMap<>();
        data.put("image1", "https://example.com/img1.jpg");
        data.put("image2", "https://example.com/img2.jpg");

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

        // 执行: 不应该抛出异常
        assertDoesNotThrow(() -> detector.detectDuplicateImages(data, elements));
    }

    @Test
    void testDetectDuplicateImages_只有一个图片元素不检测() {
        Map<String, String> data = new HashMap<>();
        data.put("image1", "https://example.com/same.jpg");

        List<PuzzleElementEntity> elements = new ArrayList<>();
        elements.add(createImageElement(1L, "image1"));

        // 执行: 不应该抛出异常
        assertDoesNotThrow(() -> detector.detectDuplicateImages(data, elements));
    }

    @Test
    void testDetectDuplicateImages_混合元素类型() {
        Map<String, String> data = new HashMap<>();
        data.put("image1", "https://example.com/same.jpg");
        data.put("text1", "标题文本");
        data.put("image2", "https://example.com/same.jpg");

        List<PuzzleElementEntity> elements = new ArrayList<>();
        elements.add(createImageElement(1L, "image1"));
        elements.add(createTextElement(2L, "text1"));
        elements.add(createImageElement(3L, "image2"));

        // 执行并验证: 应该抛出异常(两个图片相同)
        assertThrows(DuplicateImageException.class,
                () -> detector.detectDuplicateImages(data, elements));
    }

    @Test
    void testFindDuplicateRecord_找到记录() {
        // 准备数据
        Long templateId = 100L;
        String contentHash = "abc123";
        Long scenicId = 1L;

        PuzzleGenerationRecordEntity mockRecord = new PuzzleGenerationRecordEntity();
        mockRecord.setId(999L);
        mockRecord.setResultImageUrl("https://example.com/old.jpg");

        // Mock行为
        when(recordMapper.findByContentHash(templateId, contentHash, scenicId))
                .thenReturn(mockRecord);

        // 执行
        PuzzleGenerationRecordEntity result = detector.findDuplicateRecord(templateId, contentHash, scenicId);

        // 验证
        assertNotNull(result);
        assertEquals(999L, result.getId());
        assertEquals("https://example.com/old.jpg", result.getResultImageUrl());
        verify(recordMapper).findByContentHash(templateId, contentHash, scenicId);
    }

    @Test
    void testFindDuplicateRecord_未找到记录() {
        Long templateId = 100L;
        String contentHash = "abc123";
        Long scenicId = 1L;

        when(recordMapper.findByContentHash(templateId, contentHash, scenicId))
                .thenReturn(null);

        PuzzleGenerationRecordEntity result = detector.findDuplicateRecord(templateId, contentHash, scenicId);

        assertNull(result);
    }

    // 辅助方法: 创建图片元素
    private PuzzleElementEntity createImageElement(Long id, String elementKey) {
        PuzzleElementEntity element = new PuzzleElementEntity();
        element.setId(id);
        element.setElementKey(elementKey);
        element.setElementType("IMAGE"); // IMAGE类型
        return element;
    }

    // 辅助方法: 创建文本元素
    private PuzzleElementEntity createTextElement(Long id, String elementKey) {
        PuzzleElementEntity element = new PuzzleElementEntity();
        element.setId(id);
        element.setElementKey(elementKey);
        element.setElementType("TEXT"); // TEXT类型
        return element;
    }
}
