/**
 * @ProjectName: 智慧评标-主观分助手
 * @Package: com.zhpb.gdyd_zhpb_zgf.service.impl
 * @ClassName: OfficeGatewayServiceImpl
 * @Description: 办公网关服务实现（磐智宁波池）
 * @Author: 张志锋
 * @Date: 2025-11-05
 * @Version: 1.0
 * @Copyright: © 2025 智慧评标-主观分助手
 */
package com.zhpb.gdyd_zhpb_zgf.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.zhpb.gdyd_zhpb_zgf.entity.mysql.ModelRequestLog;
import com.zhpb.gdyd_zhpb_zgf.service.ModelRequestLogService;
import com.zhpb.gdyd_zhpb_zgf.utils.HttpClientUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.Base64;
import java.util.UUID;

/**
 * 办公网关服务实现
 * 实现磐智宁波池的模型网关通用协议
 */
@Service
public class OfficeGatewayServiceImpl {

    private static final Logger logger = LoggerFactory.getLogger(OfficeGatewayServiceImpl.class);

    @Value("${office-gateway.uat-url}")
    private String uatUrl;

    @Value("${office-gateway.prod-url:http://prod-gateway-url}")
    private String prodUrl;

    @Value("${office-gateway.appid}")
    private String appId;

    @Value("${office-gateway.appkey}")
    private String appKey;

    @Value("${office-gateway.capabilityname:semantic0000000000000000}")
    private String capabilityName;

    @Value("${office-gateway.embedding-model}")
    private String embeddingModel;

    @Value("${office-gateway.timeout:30000}")
    private int timeout;

    @Value("${vectorization.mode:local}")
    private String vectorizationMode;

    @Autowired(required = false)
    private ModelRequestLogService modelRequestLogService;

    /**
     * 对二进制数据进行base64编码
     */
    private String encodeBase64(byte[] rawBytes) {
        return Base64.getEncoder().encodeToString(rawBytes);
    }

    /**
     * 计算MD5哈希值
     */
    private String calculateMd5(String rawText) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hash = md.digest(rawText.getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte b : hash) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5算法不可用", e);
        }
    }

    /**
     * 确保capabilityname为24位，不足补0
     */
    private String getCapabilityName24(String rawCapabilityName) {
        if (rawCapabilityName == null) {
            rawCapabilityName = "semantic0000000000000000";
        }
        List<Character> capabilityNameList = new ArrayList<>();
        for (char c : rawCapabilityName.toCharArray()) {
            capabilityNameList.add(c);
        }
        while (capabilityNameList.size() < 24) {
            capabilityNameList.add('0');
        }
        StringBuilder sb = new StringBuilder();
        for (Character c : capabilityNameList) {
            sb.append(c);
        }
        return sb.toString();
    }

    /**
     * 生成包含授权信息的请求头
     */
    private Map<String, String> generateAuthHeaders() {
        // 生成唯一标识符
        String uuid = UUID.randomUUID().toString().replace("-", "");

        // 确保capabilityName为24位
        String capabilityName24 = getCapabilityName24(capabilityName);

        // 构建并编码X-Server-Param
        Map<String, String> xServerParam = new HashMap<>();
        xServerParam.put("appid", appId);
        xServerParam.put("csid", appId + capabilityName24 + uuid);

        String xServerParamJson = JSON.toJSONString(xServerParam);
        String xServerParamEncoded = encodeBase64(xServerParamJson.getBytes(StandardCharsets.UTF_8));

        // 生成时间戳
        String xCurTime = String.valueOf(System.currentTimeMillis() / 1000);

        // 计算校验和
        String xCheckSum = calculateMd5(appKey + xCurTime + xServerParamEncoded);

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("Accept", "application/json");
        headers.put("X-Server-Param", xServerParamEncoded);
        headers.put("X-CurTime", xCurTime);
        headers.put("X-CheckSum", xCheckSum);
        headers.put("traceId", "smart-qa-" + System.currentTimeMillis());

        return headers;
    }

    /**
     * 获取当前使用的URL（UAT或生产）
     */
    private String getCurrentUrl() {
        // 可以根据环境变量或其他配置来决定使用UAT还是生产环境
        String env = System.getProperty("spring.profiles.active", "default");
        if ("prod".equals(env) || "production".equals(env)) {
            return prodUrl;
        }
        return uatUrl;
    }

    /**
     * 调用Embedding模型进行文本向量化
     *
     * @param texts 待向量化的文本列表
     * @return 向量结果列表
     */
    public List<float[]> embedTexts(List<String> texts) {
        if (!"office".equals(vectorizationMode)) {
            throw new IllegalStateException("当前向量化模式不是办公网关模式");
        }

        try {
            logger.info("调用办公网关Embedding模型，文本数量: {}", texts.size());

            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("model_type", "embedding");
            requestBody.put("model_name", embeddingModel);

            Map<String, Object> params = new HashMap<>();
            params.put("texts", texts);
            requestBody.put("params", params);

            // 发送请求
            String responseStr = callGatewayApi(JSON.toJSONString(requestBody),
                    "VECTORIZE_OFFICE", embeddingModel);
            JSONObject response = JSON.parseObject(responseStr);

            // 检查响应
            String code = response.getString("code");
            if (!"000000".equals(code)) {
                String desc = response.getString("desc");
                throw new RuntimeException("办公网关API调用失败: " + code + " - " + desc);
            }

            // 解析结果
            JSONObject result = response.getJSONObject("result");
            JSONArray embeddings = result.getJSONArray("embeddings");

            List<float[]> vectors = new ArrayList<>();
            for (int i = 0; i < embeddings.size(); i++) {
                JSONObject embedding = embeddings.getJSONObject(i);
                JSONArray embeddingArray = embedding.getJSONArray("embedding");

                float[] vector = new float[embeddingArray.size()];
                for (int j = 0; j < embeddingArray.size(); j++) {
                    vector[j] = embeddingArray.getFloat(j);
                }
                vectors.add(vector);
            }

            logger.info("办公网关Embedding成功，返回向量数量: {}", vectors.size());
            return vectors;

        } catch (Exception e) {
            logger.error("调用办公网关Embedding失败", e);
            throw new RuntimeException("办公网关Embedding调用失败: " + e.getMessage());
        }
    }

    /**
     * 调用Reranker模型进行文档重排序
     *
     * @param query 查询文本
     * @param documents 候选文档列表，每个文档包含id和content
     * @param topK 返回前K个结果，可选
     * @return 重排序后的文档ID和分数
     */
    public List<Map<String, Object>> rerankDocuments(String query, List<Map<String, Object>> documents, Integer topK) {
        try {
            logger.info("调用办公网关Reranker模型，文档数量: {}", documents.size());

            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("model_type", "reranker");
            requestBody.put("model_name", "rerank-bge-v2-m3"); // 使用默认的reranker模型

            Map<String, Object> params = new HashMap<>();
            params.put("query", query);
            params.put("documents", documents);
            if (topK != null && topK > 0) {
                params.put("top_k", topK);
            }
            requestBody.put("params", params);

            // 发送请求
            String responseStr = callGatewayApi(JSON.toJSONString(requestBody),
                    "OFFICE_RERANK", "rerank-bge-v2-m3");
            JSONObject response = JSON.parseObject(responseStr);

            // 检查响应
            String code = response.getString("code");
            if (!"000000".equals(code)) {
                String desc = response.getString("desc");
                throw new RuntimeException("办公网关Reranker API调用失败: " + code + " - " + desc);
            }

            // 解析结果
            JSONObject result = response.getJSONObject("result");
            JSONArray results = result.getJSONArray("results");

            List<Map<String, Object>> rankedResults = new ArrayList<>();
            for (int i = 0; i < results.size(); i++) {
                JSONObject item = results.getJSONObject(i);
                Map<String, Object> rankedItem = new HashMap<>();
                rankedItem.put("id", item.getString("id"));
                rankedItem.put("score", item.getDouble("score"));
                rankedResults.add(rankedItem);
            }

            logger.info("办公网关Reranker成功，返回结果数量: {}", rankedResults.size());
            return rankedResults;

        } catch (Exception e) {
            logger.error("调用办公网关Reranker失败", e);
            throw new RuntimeException("办公网关Reranker调用失败: " + e.getMessage());
        }
    }

    /**
     * 调用办公网关API
     */
    private String callGatewayApi(String requestBody, String requestSource, String modelName) throws Exception {
        String url = getCurrentUrl();
        logger.debug("调用办公网关API: {} , 请求体长度: {}", url, requestBody.length());

        Map<String, String> headers = generateAuthHeaders();
        long startTime = System.currentTimeMillis();
        String response = null;
        boolean success = false;
        String errorMsg = null;
        try {
            response = HttpClientUtils.postJson(url, requestBody, headers);
            if (response == null || response.trim().isEmpty()) {
                throw new RuntimeException("办公网关API无响应");
            }
            logger.debug("办公网关API响应长度: {}", response.length());
            success = true;
            return response;
        } catch (Exception e) {
            errorMsg = e.getMessage();
            throw e;
        } finally {
            recordGatewayModelLog(
                requestSource,
                modelName,
                url,
                requestBody,
                response,
                System.currentTimeMillis() - startTime,
                success,
                errorMsg,
                headers
            );
        }
    }

    private void recordGatewayModelLog(String requestSource,
                                       String modelName,
                                       String requestUrl,
                                       String requestBody,
                                       String responseBody,
                                       Long durationMs,
                                       boolean success,
                                       String errorMessage,
                                       Map<String, String> headers) {
        if (modelRequestLogService == null) {
            return;
        }
        ModelRequestLog logEntry = new ModelRequestLog();
        logEntry.setRequestSource(requestSource);
        logEntry.setRequestUrl(requestUrl);
        logEntry.setRequestMethod("POST");
        logEntry.setModelName(modelName);
        logEntry.setRequestPayload(requestBody);
        logEntry.setResponsePayload(responseBody);
        logEntry.setStatus(success ? "SUCCESS" : "FAILED");
        logEntry.setDurationMs(durationMs);
        logEntry.setAppKey(appKey);
        logEntry.setAppSecret(capabilityName);
        logEntry.setErrorMessage(errorMessage);
        if (headers != null) {
            logEntry.setExtraInfo(String.format("X-Server-Param=%s;X-CurTime=%s;X-CheckSum=%s",
                headers.get("X-Server-Param"),
                headers.get("X-CurTime"),
                headers.get("X-CheckSum")));
        }
        modelRequestLogService.record(logEntry);
    }

    /**
     * 批量向量化文本（支持异步）
     */
    public CompletableFuture<List<float[]>> embedTextsAsync(List<String> texts) {
        return CompletableFuture.supplyAsync(() -> embedTexts(texts));
    }

    /**
     * 获取当前配置的嵌入模型名称
     */
    public String getEmbeddingModel() {
        return embeddingModel;
    }
}
