package com.emoon.tongue.service.impl;

import com.emoon.tongue.domain.vo.KeyFeatures;
import com.emoon.tongue.domain.vo.TongueDiagnosisDetailVo;
import com.emoon.tongue.domain.vo.TongueDiagnosisInfo;
import com.emoon.tongue.service.ai.TongueAiDiagnosisProvider;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
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 java.nio.charset.StandardCharsets;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 真实AI舌诊诊断服务实现类
 *
 * @author destiny
 * @date 2025-12-21
 */
@Slf4j
@Service
public class TongueAiRealDiagnosisService implements TongueAiDiagnosisProvider {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @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;

    /**
     * 建议放在配置/环境变量里：ai.dashscope.api-key
     * 如果为空，会触发异常并在上层fallback到mock
     */
    @Value("${ai.dashscope.api-key:}")
    private String dashScopeApiKey;

    @Override
    public String provider() {
        return "dashscope";
    }

    @Override
    public TongueDiagnosisInfo diagnose(TongueDiagnosisDetailVo detail) {
        return performRealDiagnosis(detail);
    }

    /**
     * 执行真实AI舌诊诊断
     *
     * @param detail 舌诊详情（包含图片URL和患者信息）
     * @return 诊断结果
     */
    public TongueDiagnosisInfo performRealDiagnosis(TongueDiagnosisDetailVo detail) {
        log.info("开始调用真实AI模型进行舌诊诊断，图片URL: {}",
                detail.getTongueImage() != null ? detail.getTongueImage().getUrl() : "null");

        try {
            // 调用阿里云DashScope AI API进行诊断
            String aiResponse = callDashScopeDiagnosisAPI(detail);
            log.info("AI API调用完成，响应长度: {}", aiResponse != null ? aiResponse.length() : 0);

            // 解析AI响应并构建诊断结果
            return parseDiagnosisResponse(aiResponse, detail);

        } catch (Exception e) {
            log.error("真实AI诊断调用失败，切换到mock模式", e);
            log.info("返回mock诊断结果作为fallback");
            return TongueDiagnosisInfo.generateMockResult();
        }
    }

    /**
     * 调用阿里云DashScope AI诊断API
     */
    private String callDashScopeDiagnosisAPI(TongueDiagnosisDetailVo detail) throws Exception {
        // 构建请求体
        Map<String, Object> requestBody = buildDiagnosisRequest(detail);

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

    /**
     * 构建诊断请求体
     */
    private Map<String, Object> buildDiagnosisRequest(TongueDiagnosisDetailVo detail) {
        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", detail.getTongueImage().getUrl());
        imageContent.put("image_url", imageUrlMap);
        content.add(imageContent);

        // 文本内容（诊断规则 + 主诉信息）
        Map<String, Object> textContent = new HashMap<>();
        textContent.put("type", "text");

        String chiefComplaint = "";
        if (detail.getPatientInfo() != null && detail.getPatientInfo().getPatientChiefComplaint() != null) {
            chiefComplaint = detail.getPatientInfo().getPatientChiefComplaint();
        }

        String diagnosisPrompt = getDiagnosisPrompt(chiefComplaint);
        textContent.put("text", diagnosisPrompt);
        content.add(textContent);

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

        return requestBody;
    }

    /**
     * 获取诊断提示词
     */
    private String getDiagnosisPrompt(String chiefComplaint) {
        String basePrompt = "### 角色定位\n" +
                "你是一名资深中医舌诊专家，需基于上传的舌象图片完成专业舌诊分析，并严格按照指定JSON格式输出结果，不得添加任何额外文字、解释或备注。\n" +
                "### 诊断规则\n" +
                "1. **特征提取规则**：\n" +
                "   - 舌色仅从以下选项选择：淡红舌、淡白舌、红舌、青舌、黯舌、红黯舌、红青舌、黯红舌、青红舌\n" +
                "   - 舌形仅从以下选项选择：老舌、嫩舌、胖大舌、肿胀舌、瘦薄舌、点刺舌、裂纹舌、齿痕舌\n" +
                "   - 舌态仅从以下选项选择：萎软舌、强硬舌、歪斜舌、颤动舌、吐弄舌、缩短舌\n" +
                "   - 苔质仅从以下选项选择：无苔 (全剥苔，镜面舌)、花剥苔 (地图舌)、少苔、薄苔、厚苔、润苔、滑苔、燥苔、腐苔、腻苔\n" +
                "   - 苔色仅从以下选项选择：白苔、淡黄、黄、焦黄、灰苔、黑苔、舌边白涎\n" +
                "   - 每个特征维度仅输出1个最匹配的结果，置信度为0.00-1.00之间的数值（保留2位小数），反映该特征判断的可信度。\n" +
                "2. **输出内容规则**：\n" +
                "   - tongueGeneralDesc：整合舌色、舌形、舌态、苔质、苔色核心特征，结合中医理论给出1-2句话的舌象整体描述，最后补充体质判断结论。\n" +
                "   - keyFeatures：必须包含舌色、舌形、舌态、苔质、苔色五个维度，每个特征格式为「维度：结果」，置信度为0.00-1.00。\n" +
                "   - overallConfidence：整体诊断置信度，取keyFeatures中所有特征置信度的平均值（保留2位小数）。\n" +
                "   - constitutionAnalysis：基于舌象特征给出明确的体质判断（如平和质、气虚质、阴虚质、湿热质等），仅1句话。\n" +
                "   - healthAdvice：结合体质分析给出针对性的健康建议，1-2句话，符合中医养生规范。\n" +
                "### 格式强制要求\n" +
                "1. 输出结果必须是可直接解析的JSON字符串，无任何前置/后置文字（如\"以下是诊断结果：\"\"{}\"前的说明等）。\n" +
                "2. JSON字段名严格匹配：tongueGeneralDesc、keyFeatures、overallConfidence、constitutionAnalysis、healthAdvice，不得增减字段、修改字段名。\n" +
                "3. 数值类字段（置信度）必须为字符串类型且保留2位小数，keyFeatures为数组格式，数组内每个元素包含feature和confidence字段。\n";

        if (!chiefComplaint.isEmpty()) {
            basePrompt += "### 患者主诉信息\n" +
                    "患者主诉：" + chiefComplaint + "。请结合患者主诉信息进行体质分析和健康建议。\n";
        }

        basePrompt += "### 输出格式说明\n" +
                "请严格按照以下JSON格式输出分析结果，字段名必须完全匹配，不得增减字段：\n" +
                "{\"tongueGeneralDesc\":\"整体舌象描述\",\"keyFeatures\":[{\"feature\":\"特征描述\",\"confidence\":\"0.85\"}],\"overallConfidence\":\"0.88\",\"constitutionAnalysis\":\"体质分析结论\",\"healthAdvice\":\"健康建议内容\"}\n\n" +
                "### 分析要求\n" +
                "- 根据舌象图片的实际特征进行客观分析\n" +
                "- constitutionAnalysis字段请基于中医理论和舌象特征进行独立判断\n" +
                "- healthAdvice请根据体质分析结果提供针对性建议\n" +
                "- 置信度基于特征的明显程度进行合理评估";

        return basePrompt;
    }

    /**
     * 发送诊断HTTP请求
     */
    private String sendDiagnosisHttpRequest(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");

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

            // 发送请求
            httpClient = HttpClients.createDefault();
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            responseContent = EntityUtils.toString(entity, StandardCharsets.UTF_8);

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

        return responseContent;
    }

    /**
     * 解析诊断响应
     */
    private TongueDiagnosisInfo parseDiagnosisResponse(String aiResponse, TongueDiagnosisDetailVo detail) {
        log.info("开始解析AI诊断响应，原始响应长度: {}", aiResponse != null ? aiResponse.length() : 0);

        try {
            // 解析DashScope API响应
            JsonNode rootNode = objectMapper.readTree(aiResponse);
            log.debug("成功解析根节点");

            JsonNode choicesNode = rootNode.get("choices");
            log.debug("choices节点: {}", choicesNode);

            if (choicesNode != null && choicesNode.isArray() && choicesNode.size() > 0) {
                JsonNode messageNode = choicesNode.get(0).get("message");
                log.debug("message节点: {}", messageNode);

                if (messageNode != null) {
                    String content = messageNode.get("content").asText();
                    log.info("AI诊断结果内容: {}", content);

                    try {
                        // 解析JSON内容
                        JsonNode diagnosisJson = objectMapper.readTree(content);
                        log.info("成功解析AI返回的JSON内容: {}", content);

                        // 构建TongueDiagnosisInfo对象
                        TongueDiagnosisInfo diagnosisInfo = new TongueDiagnosisInfo();

                        // 设置基本字段
                        if (diagnosisJson.has("tongueGeneralDesc")) {
                            diagnosisInfo.setTongueGeneralDesc(diagnosisJson.get("tongueGeneralDesc").asText());
                            log.debug("设置tongueGeneralDesc: {}", diagnosisInfo.getTongueGeneralDesc());
                        }

                        // 解析keyFeatures
                        JsonNode keyFeaturesNode = diagnosisJson.get("keyFeatures");
                        List<KeyFeatures> keyFeatures = new ArrayList<>();
                        String tongueColorResult = null;
                        String tongueCoatingResult = null;
                        String tongueShapeResult = null;

                        log.info("开始解析keyFeatures，节点是否存在: {}, 是否为数组: {}",
                                keyFeaturesNode != null, keyFeaturesNode != null && keyFeaturesNode.isArray());

                        if (keyFeaturesNode != null && keyFeaturesNode.isArray()) {
                            log.info("解析keyFeatures，共{}个特征", keyFeaturesNode.size());
                            for (JsonNode featureNode : keyFeaturesNode) {
                                try {
                                    String featureText = featureNode.get("feature").asText();
                                    BigDecimal confidence = new BigDecimal(featureNode.get("confidence").asText());

                                    log.info("处理特征: {} - {}", featureText, confidence);

                                    KeyFeatures feature = new KeyFeatures();
                                    feature.setFeature(featureText);
                                    feature.setConfidence(confidence);
                                    keyFeatures.add(feature);

                                    // 从特征中提取舌色、舌苔、舌形信息
                                    if (featureText.startsWith("舌色：")) {
                                        tongueColorResult = featureText.substring(3);
                                        log.info("提取到舌色: {}", tongueColorResult);
                                    } else if (featureText.startsWith("苔色：")) {
                                        tongueCoatingResult = featureText.substring(3);
                                        log.info("提取到舌苔: {}", tongueCoatingResult);
                                    } else if (featureText.startsWith("舌形：")) {
                                        tongueShapeResult = featureText.substring(3);
                                        log.info("提取到舌形: {}", tongueShapeResult);
                                    }
                                } catch (Exception e) {
                                    log.error("解析单个特征失败: {}, 错误: {}", featureNode, e.getMessage(), e);
                                }
                            }
                        } else {
                            log.warn("keyFeatures节点为空或不是数组");
                        }

                        diagnosisInfo.setKeyFeatures(keyFeatures);
                        log.info("设置keyFeatures完成，共{}个特征", keyFeatures.size());

                        // 设置提取出的舌色、舌苔、舌形结果
                        log.info("准备设置提取结果 - 舌色: {}, 舌苔: {}, 舌形: {}",
                                tongueColorResult, tongueCoatingResult, tongueShapeResult);

                        if (tongueColorResult != null) {
                            diagnosisInfo.setTongueColorResult(tongueColorResult);
                            log.info("设置舌色结果: {}", tongueColorResult);
                        }
                        if (tongueCoatingResult != null) {
                            diagnosisInfo.setTongueCoatingResult(tongueCoatingResult);
                            log.info("设置舌苔结果: {}", tongueCoatingResult);
                        }
                        if (tongueShapeResult != null) {
                            diagnosisInfo.setTongueShapeResult(tongueShapeResult);
                            log.info("设置舌形结果: {}", tongueShapeResult);
                        }

                        // 设置其他字段
                        if (diagnosisJson.has("overallConfidence")) {
                            diagnosisInfo.setOverallConfidence(new BigDecimal(diagnosisJson.get("overallConfidence").asText()));
                            log.debug("设置overallConfidence: {}", diagnosisInfo.getOverallConfidence());
                        }

                        if (diagnosisJson.has("constitutionAnalysis")) {
                            diagnosisInfo.setConstitutionAnalysis(diagnosisJson.get("constitutionAnalysis").asText());
                            log.debug("设置constitutionAnalysis: {}", diagnosisInfo.getConstitutionAnalysis());
                        }

                        if (diagnosisJson.has("healthAdvice")) {
                            diagnosisInfo.setHealthAdvice(diagnosisJson.get("healthAdvice").asText());
                            log.debug("设置healthAdvice: {}", diagnosisInfo.getHealthAdvice());
                        }

                        log.info("AI诊断结果解析完成，返回真实结果");
                        return diagnosisInfo;

                    } catch (Exception e) {
                        log.error("解析AI返回的JSON内容失败", e);
                        log.warn("AI诊断响应JSON解析失败，使用mock结果");
                        return TongueDiagnosisInfo.generateMockResult();
                    }
                }
            }

            // 如果解析失败，返回mock结果
            log.warn("AI诊断响应解析失败，使用mock结果");
            return TongueDiagnosisInfo.generateMockResult();

        } catch (Exception e) {
            log.error("解析AI诊断响应失败: {}", aiResponse, e);
            // 解析失败时，返回mock结果
            return TongueDiagnosisInfo.generateMockResult();
        }
    }
}





