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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 拼图去重检测器
 * 负责检测重复内容和重复图片,避免不必要的图片生成
 *
 * @author Claude
 * @since 2025-01-21
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PuzzleDuplicationDetector {
    private final Set<String> skippedElementKeys = Set.of();
    private final PuzzleGenerationRecordMapper recordMapper;

    /**
     * 计算内容哈希
     * 基于所有元素的实际内容值(按elementKey排序后拼接)计算SHA256哈希
     *
     * @param finalData 最终的元素数据映射(elementKey -> value)
     * @return SHA256哈希值(64位16进制字符串)
     */
    public String calculateContentHash(Map<String, String> finalData) {
        if (finalData == null || finalData.isEmpty()) {
            log.warn("计算内容哈希时发现空数据,返回空哈希");
            return "";
        }

        try {
            // 1. 按key排序,确保相同内容生成相同哈希
            List<String> sortedKeys = new ArrayList<>(finalData.keySet());
            Collections.sort(sortedKeys);

            // 2. 拼接为固定格式: "key1:value1|key2:value2|..."
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < sortedKeys.size(); i++) {
                String key = sortedKeys.get(i);
                if (skippedElementKeys.contains(key)) {
                    continue;
                }
                String value = finalData.get(key);
                sb.append(key).append(":").append(value != null ? value : "");
                if (i < sortedKeys.size() - 1) {
                    sb.append("|");
                }
            }

            String content = sb.toString();
            log.debug("内容哈希计算原文: {}", content);

            // 3. 计算SHA256
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));

            // 4. 转换为16进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }

            String hash = hexString.toString();
            log.debug("计算得到内容哈希: {}", hash);
            return hash;

        } catch (NoSuchAlgorithmException e) {
            log.error("SHA-256算法不可用", e);
            throw new RuntimeException("内容哈希计算失败: SHA-256算法不可用", e);
        }
    }

    /**
     * 检测重复图片
     * 检查所有IMAGE类型元素是否使用相同的图片URL
     * 如果发现所有图片元素使用同一个URL,抛出异常
     *
     * @param finalData 最终的元素数据映射
     * @param elements  元素列表
     * @throws DuplicateImageException 所有图片元素使用相同URL时抛出
     */
    public void detectDuplicateImages(Map<String, String> finalData, List<PuzzleElementEntity> elements) {
        if (finalData == null || finalData.isEmpty() || elements == null || elements.isEmpty()) {
            log.debug("跳过重复图片检测: 数据为空");
            return;
        }

        // 1. 筛选出所有IMAGE类型的元素(elementType="IMAGE")
        List<PuzzleElementEntity> imageElements = elements.stream()
                .filter(e -> "IMAGE".equals(e.getElementType()))
                .collect(Collectors.toList());

        if (imageElements.size() < 2) {
            log.debug("图片元素数量不足2个,跳过重复检测");
            return;
        }

        // 2. 提取所有图片元素的实际URL值
        List<String> imageUrls = new ArrayList<>();
        for (PuzzleElementEntity element : imageElements) {
            String url = finalData.get(element.getElementKey());
            if (url != null && !url.trim().isEmpty()) {
                imageUrls.add(url);
            }
        }

        if (imageUrls.isEmpty()) {
            log.debug("没有有效的图片URL,跳过重复检测");
            return;
        }

        // 3. 对URL去重
        Set<String> uniqueUrls = new HashSet<>(imageUrls);

        log.debug("重复图片检测通过: 发现{}个不同的图片URL", uniqueUrls.size());
    }

    /**
     * 查找重复记录
     * 根据模板ID、内容哈希和景区ID查询历史记录
     * 返回最新的成功生成记录(如果存在)
     *
     * @param templateId  模板ID
     * @param contentHash 内容哈希
     * @param scenicId    景区ID
     * @return 历史记录,如果不存在则返回null
     */
    public PuzzleGenerationRecordEntity findDuplicateRecord(Long templateId, String contentHash, Long scenicId) {
        if (contentHash == null || contentHash.isEmpty()) {
            log.debug("内容哈希为空,跳过去重查询");
            return null;
        }

        try {
            PuzzleGenerationRecordEntity record = recordMapper.findByContentHash(templateId, contentHash, scenicId);

            if (record != null) {
                log.info("发现重复内容: templateId={}, contentHash={}, 历史记录ID={}, imageUrl={}",
                        templateId, contentHash, record.getId(), record.getResultImageUrl());
            } else {
                log.debug("未发现重复内容: templateId={}, contentHash={}", templateId, contentHash);
            }

            return record;

        } catch (Exception e) {
            log.error("查询重复记录失败: templateId={}, contentHash={}", templateId, contentHash, e);
            // 查询失败时返回null,继续正常生成流程
            return null;
        }
    }
}
