package com.emoon.tongue.service.impl;

import com.emoon.tongue.domain.vo.TongueImageCheckVo;
import com.emoon.tongue.service.ITongueImageCheckService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.yaml.snakeyaml.Yaml;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * 舌象图片校验服务实现类
 *
 * @author destiny
 * @date 2025-12-11
 */
@Slf4j
@Service
public class TongueImageCheckServiceImpl implements ITongueImageCheckService {

    private final Random random = new Random();
    private final ObjectMapper objectMapper;
    private List<Map<String, Object>> checkRules;

    @Value("${ai.mock-flag:true}")
    private boolean mockFlag;

    @Value("${ai.dashscope.url:https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions}")
    private String dashScopeUrl;

    @Value("${ai.dashscope.model:qwen3-vl-plus}")
    private String dashScopeModel;

    @Value("${ai.dashscope.api-key:}")
    private String dashScopeApiKey;

    public TongueImageCheckServiceImpl() {
        this.objectMapper = new ObjectMapper();
        loadCheckRules();
    }


    /**
     * 加载校验规则
     */
    private void loadCheckRules() {
        try {
            Yaml yaml = new Yaml();
            InputStream inputStream = this.getClass().getClassLoader()
                .getResourceAsStream("tongue-image-check-rules.yml");
            if (inputStream != null) {
                Map<String, Object> data = yaml.load(inputStream);
                this.checkRules = (List<Map<String, Object>>) data.get("tongueImageCheckRules");
                log.info("舌象图片校验规则加载成功，共{}条规则", this.checkRules.size());
            }
        } catch (Exception e) {
            log.error("加载舌象图片校验规则失败", e);
        }
    }

    @Override
    public TongueImageCheckVo checkTongueImage(String imageUrl) {
        log.info("开始校验舌象图片: {}, Mock模式: {}", imageUrl, mockFlag);

        TongueImageCheckVo result = new TongueImageCheckVo();

        if (mockFlag) {
            // Mock模式：随机概率模拟校验结果
            log.info("使用Mock模式进行图片校验");
            performMockCheck(result);
        } else {
            // 真实AI模式：调用真实图片校验服务
            log.info("使用真实AI模式进行图片校验 - URL: {}", imageUrl);
            performRealCheck(imageUrl, result);
            log.info("AI校验结果 - 错误码: {}, 错误类型: '{}', 通过: {}", result.getErrorCode(), result.getErrorType(), result.getPassed());
        }

        return result;
    }

    /**
     * Mock校验实现
     */
    private void performMockCheck(TongueImageCheckVo result) {
        // Mock实现：50%概率通过，50%概率随机返回一个错误
        if (random.nextDouble() < 0.5) {
            // 通过校验
            result.setErrorCode(0);
            result.setErrorType("");
            result.setJudgeStandard("");
            result.setOptimizeSuggestion("");
            result.setPassed(true);
            log.info("舌象图片校验通过");
        } else {
            // 随机选择一个错误规则
            if (checkRules != null && !checkRules.isEmpty()) {
                Map<String, Object> randomRule = checkRules.get(random.nextInt(checkRules.size()));

                result.setErrorCode((Integer) randomRule.get("errorCode"));
                result.setErrorType((String) randomRule.get("errorType"));
                result.setJudgeStandard((String) randomRule.get("judgeStandard"));
                result.setOptimizeSuggestion((String) randomRule.get("optimizeSuggestion"));
                result.setPassed(false);

                log.info("舌象图片校验不通过，错误码: {}, 错误类型: {}",
                    result.getErrorCode(), result.getErrorType());
            } else {
                // 如果规则加载失败，默认通过
                result.setErrorCode(0);
                result.setPassed(true);
            }
        }
    }

    /**
     * 真实AI校验实现
     */
    private void performRealCheck(String imageUrl, TongueImageCheckVo result) {
        try {
            // 调用阿里云DashScope AI API进行图片校验
            String aiResponse = callDashScopeAPI(imageUrl);

            // 解析AI响应并设置结果
            parseAIResponse(aiResponse, result);

        } catch (Exception e) {
            log.error("真实AI图片校验异常", e);
            // 校验失败时，默认通过（避免阻塞流程）
            result.setErrorCode(0);
            result.setPassed(true);
        }
    }

    /**
     * 调用阿里云DashScope API
     */
    private String callDashScopeAPI(String imageUrl) throws Exception {
        // 构建请求体
        Map<String, Object> requestBody = buildDashScopeRequest(imageUrl);

        // 发送HTTP请求
        return sendHttpRequest(dashScopeUrl, requestBody);
    }

    /**
     * 构建DashScope请求体
     */
    private Map<String, Object> buildDashScopeRequest(String imageUrl) {
        Map<String, Object> requestBody = new HashMap<>();

        // 模型配置
        requestBody.put("model", dashScopeModel);

        // 消息内容
        List<Map<String, Object>> messages = new ArrayList<>();
        Map<String, Object> message = new HashMap<>();
        message.put("role", "user");

        List<Map<String, Object>> content = new ArrayList<>();

        // 图片内容
        Map<String, Object> imageContent = new HashMap<>();
        imageContent.put("type", "image_url");
        Map<String, Object> imageUrlMap = new HashMap<>();
        imageUrlMap.put("url", imageUrl);
        imageContent.put("image_url", imageUrlMap);
        content.add(imageContent);

        // 文本内容（校验规则）
        Map<String, Object> textContent = new HashMap<>();
        textContent.put("type", "text");
        textContent.put("text", getValidationRules());
        content.add(textContent);

        message.put("content", content);
        messages.add(message);
        requestBody.put("messages", messages);

        return requestBody;
    }

    /**
     * 获取校验规则文本
     */
    private String getValidationRules() {
        return "你是一名舌象诊断专业校验人员，请按照以下规则对舌象照片进行检测，判断标准请尽量宽松，以用户友好为主：\n" +
            "1. 首先判断照片是否基本符合舌象检测要求，若照片质量一般但仍可用于诊断，请优先考虑通过\n" +
            "2. 错误类型及判断标准如下（请谨慎使用，仅在明显影响诊断时才判定为错误）：\n" +
            "- 【图片质量问题】：仅当图片质量严重下降、舌面基本无法辨认时\n" +
            "- 【舌体模糊（对焦失败）】：仅当舌面严重模糊、无法辨认舌苔和舌质时\n" +
            "- 【光线异常（过亮/过暗）】：仅当光线导致舌面细节完全丢失、无法进行任何诊断时\n" +
            "- 【构图不规范】：仅当舌体完全超出取景框、无法观察到任何舌面时\n" +
            "- 【舌体遮挡】：仅当严重影响舌面观察时\n" +
            "- 【拍摄角度错误】：仅当角度导致舌面严重变形、无法正常观察时\n" +
            "- 【背景/干扰元素】：仅当背景严重干扰舌面观察、影响诊断准确性时\n" +
            "- 【内容非舌象】：拍摄对象明显不是舌头时\n" +
            "- 【舌体状态异常】：仅当舌体状态严重异常、无法进行正常诊断时\n" +
            "- 【色彩/曝光失真】：仅当色彩失真严重、无法辨认舌色时\n" +
            "- 【运动模糊】：仅当模糊严重、舌面轮廓完全不可辨认时\n" +
            "3. 检测要求：\n" +
            "- 请优先考虑照片的可用性，只要基本能用于舌诊诊断就应该通过\n" +
            "- 除非存在严重问题，否则请不要轻易判定为失败\n" +
            "- 若照片质量一般但仍可辨认舌象特征，请返回通过\n" +
            "- 输出格式：如果通过，返回空字符串；如果失败，仅返回上述错误类型中的一项文字内容，无需额外解释";
    }

    /**
     * 发送HTTP请求
     */
    private String sendHttpRequest(String url, Map<String, Object> requestBody) throws Exception {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        String responseContent = null;

        try {
            // 创建POST请求
            HttpPost httpPost = new HttpPost(url);

            // 设置请求头
            httpPost.setHeader("Accept", "*/*");
            httpPost.setHeader("Accept-Encoding", "gzip, deflate, br");
            if (dashScopeApiKey == null || dashScopeApiKey.trim().isEmpty()) {
                throw new IllegalStateException("未配置 ai.dashscope.api-key");
            }
            httpPost.setHeader("Authorization", "Bearer " + dashScopeApiKey.trim());
            httpPost.setHeader("Connection", "keep-alive");
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setHeader("User-Agent", "PostmanRuntime-ApipostRuntime/1.1.0");

            // 将Map转换为JSON字符串
            String jsonParam = objectMapper.writeValueAsString(requestBody);
            httpPost.setEntity(new StringEntity(jsonParam, "UTF-8"));

            // 发送请求
            httpClient = HttpClients.createDefault();
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            responseContent = EntityUtils.toString(entity, "UTF-8");

        } finally {
            try {
                if (response != null) response.close();
                if (httpClient != null) httpClient.close();
            } catch (Exception e) {
                log.warn("关闭HTTP连接异常", e);
            }
        }

        return responseContent;
    }

    /**
     * 解析AI响应
     */
    private void parseAIResponse(String aiResponse, TongueImageCheckVo result) {
        try {
            // 解析DashScope API响应
            JsonNode rootNode = objectMapper.readTree(aiResponse);
            JsonNode choicesNode = rootNode.get("choices");

            if (choicesNode != null && choicesNode.isArray() && choicesNode.size() > 0) {
                JsonNode messageNode = choicesNode.get(0).get("message");
                if (messageNode != null) {
                    String content = messageNode.get("content").asText();
                    log.info("AI校验结果: {}", content);

                    // 根据AI返回的内容判断是否通过
                    if (content == null || content.trim().isEmpty()) {
                        // 内容为空，认为通过
                        setPassResult(result);
                    } else if (isErrorType(content.trim())) {
                        // 识别为错误类型
                        setErrorResult(result, content.trim());
                    } else {
                        // 其他情况，认为通过
                        setPassResult(result);
                    }
                } else {
                    // 没有message节点，默认通过
                    setPassResult(result);
                }
            } else {
                // 没有choices或为空，默认通过
                setPassResult(result);
            }

        } catch (Exception e) {
            log.error("解析AI响应失败: {}", aiResponse, e);
            // 解析失败时，默认通过
            setPassResult(result);
        }
    }

    /**
     * 判断是否为预定义的错误类型
     */
    private boolean isErrorType(String content) {
        String[] errorTypes = {
            "图片质量问题",
            "舌体模糊（对焦失败）",
            "光线异常（过亮/过暗）",
            "构图不规范",
            "舌体遮挡",
            "拍摄角度错误",
            "背景/干扰元素",
            "内容非舌象",
            "舌体状态异常",
            "色彩/曝光失真",
            "运动模糊"
        };

        for (String errorType : errorTypes) {
            if (content.contains(errorType)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 设置校验通过结果
     */
    private void setPassResult(TongueImageCheckVo result) {
        result.setErrorCode(0);
        result.setErrorType("");
        result.setJudgeStandard("");
        result.setOptimizeSuggestion("");
        result.setPassed(true);
    }

    /**
     * 设置校验失败结果
     */
    private void setErrorResult(TongueImageCheckVo result, String errorType) {
        result.setErrorCode(1);
        result.setErrorType(errorType);
        result.setJudgeStandard("AI检测到图片存在质量问题");
        result.setOptimizeSuggestion("请重新拍摄，确保符合拍摄要求");
        result.setPassed(false);
    }
}
