/**
 * @ProjectName: 智慧评标-主观分助手
 * @Package: com.zhpb.gdyd_zhpb_zgf.service.impl
 * @ClassName: VectorizationServiceImpl
 * @Description: 向量化服务实现
 * @Author: 张志锋
 * @Date: 2025-11-05
 * @Version: 1.0
 * @Copyright: © 2025 智慧评标-主观分助手
 */
package com.zhpb.gdyd_zhpb_zgf.service.impl;

import com.zhpb.gdyd_zhpb_zgf.entity.mysql.ModelRequestLog;
import com.zhpb.gdyd_zhpb_zgf.service.ModelRequestLogService;
import com.zhpb.gdyd_zhpb_zgf.service.VectorizationService;
import com.zhpb.gdyd_zhpb_zgf.utils.VectorizeUtils;
import com.zhpb.gdyd_zhpb_zgf.utils.VectorizeUtils.VectorizeRequestException;
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.core.env.Environment;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 向量化服务实现
 * 支持三种向量化模式：local（本地）、online（在线API）、office（办公网关）
 */
@Service
public class VectorizationServiceImpl implements VectorizationService {

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

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

    @Value("${vectorize.base-url:http://localhost:8001}")
    private String vectorizeBaseUrl;

    @Value("${vectorize.api-path:/vectorize}")
    private String vectorizeApiPath;

    @Value("${vectorize.api-key:}")
    private String vectorizeApiKey;

    @Value("${vectorize.model:}")
    private String vectorizeModel;

    @Value("${vector-limits.default.max-chars:0}")
    private int defaultMaxChars;

    @Value("${vector-limits.default.max-tokens:0}")
    private int defaultMaxTokens;

    @Value("${vectorization.batch-size:10}")
    private int batchSize;

    @Autowired
    private OfficeGatewayServiceImpl officeGatewayService;

    @Autowired
    private Environment environment;

    @Autowired
    private ModelRequestLogService modelRequestLogService;

    @Override
    public float[] vectorizeText(String text) {
        try {
            List<float[]> results = vectorizeTexts(List.of(text));
            return results.isEmpty() ? new float[0] : results.get(0);
        } catch (Exception e) {
            logger.error("单文本向量化失败", e);
            throw new RuntimeException("向量化失败: " + e.getMessage());
        }
    }

    @Override
    public List<float[]> vectorizeTexts(List<String> texts) {
        logger.info("开始向量化文本，模式: {}, 文本数量: {}", vectorizationMode, texts.size());

        LimitSettings limitSettings = resolveLimitSettings();
        List<String> normalizedTexts = normalizeTexts(texts, limitSettings);
        String modelKey = limitSettings.getModelKey();

        try {
            switch (vectorizationMode.toLowerCase()) {
                case "office":
                    return vectorizeWithOfficeGateway(normalizedTexts);
                case "online":
                    return vectorizeWithOnlineApi(normalizedTexts, modelKey);
                case "local":
                default:
                    return vectorizeWithLocalService(normalizedTexts, modelKey);
            }
        } catch (Exception e) {
            logger.error("向量化失败，模式: {}", vectorizationMode, e);
            throw new RuntimeException("向量化失败: " + e.getMessage());
        }
    }

    @Override
    public int getDimension() {
        // 根据不同模式返回不同的维度
        switch (vectorizationMode.toLowerCase()) {
            case "office":
                // 办公网关embed-qwen3-8b模型的维度
                return 1024; // 根据embed-qwen3-8b的实际维度调整
            case "online":
            case "local":
            default:
                // 如果配置了 OpenAI 模型，返回 1536（text-embedding-ada-002 的维度）
                if (vectorizeModel != null && !vectorizeModel.trim().isEmpty()) {
                    // OpenAI text-embedding-ada-002 的维度是 1536
                    if (vectorizeModel.contains("ada-002") || vectorizeModel.contains("text-embedding")) {
                        return 1536;
                    }
                }
                return 896; // 默认维度
        }
    }

    /**
     * 使用办公网关进行向量化
     */
    private List<float[]> vectorizeWithOfficeGateway(List<String> texts) {
        logger.info("使用办公网关进行向量化，批次大小: {}", batchSize);

        List<float[]> allVectors = new ArrayList<>();

        // 分批处理
        for (int i = 0; i < texts.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, texts.size());
            List<String> batch = texts.subList(i, endIndex);

            try {
                List<float[]> batchVectors = officeGatewayService.embedTexts(batch);
                allVectors.addAll(batchVectors);

                logger.debug("办公网关向量化批次完成: {}-{}", i, endIndex);
            } catch (Exception e) {
                logger.error("办公网关向量化批次失败: {}-{}", i, endIndex, e);
                // 为失败的批次添加空向量
                for (int j = 0; j < batch.size(); j++) {
                    allVectors.add(new float[getDimension()]);
                }
            }
        }

        return allVectors;
    }

    /**
     * 使用在线API进行向量化
     */
    private List<float[]> vectorizeWithOnlineApi(List<String> texts, String modelKey) {
        logger.info("使用在线API进行向量化");

        List<float[]> vectors = new ArrayList<>();

        for (String text : texts) {
            try {
                VectorizeUtils.VectorizeResult result = VectorizeUtils.vectorize(
                    text, vectorizeBaseUrl, vectorizeApiPath, vectorizeApiKey, vectorizeModel);
                vectors.add(result.getVector());

                recordVectorizeLog(
                    "VECTORIZE_ONLINE",
                    result.getModel() != null ? result.getModel() : modelKey,
                    result.getRequestUrl(),
                    result.getRequestPayload(),
                    result.getResponsePayload(),
                    result.getDurationMs(),
                    true,
                    null,
                    result.getApiKey(),
                    result.getPromptTokens(),
                    result.getCompletionTokens(),
                    result.getTotalTokens()
                );
            } catch (Exception e) {
                logger.error("在线API向量化单文本失败: {}", text.substring(0, Math.min(100, text.length())), e);
                // 添加空向量
                vectors.add(new float[getDimension()]);

                if (e instanceof VectorizeRequestException vex) {
                    recordVectorizeLog(
                        "VECTORIZE_ONLINE",
                        vex.getModel() != null ? vex.getModel() : modelKey,
                        vex.getRequestUrl(),
                        vex.getRequestPayload(),
                        vex.getResponsePayload(),
                        vex.getDurationMs(),
                        false,
                        vex.getMessage(),
                        vex.getApiKey(),
                        null,
                        null,
                        null
                    );
                } else {
                    recordVectorizeLog(
                        "VECTORIZE_ONLINE",
                        modelKey,
                        null,
                        null,
                        null,
                        null,
                        false,
                        e.getMessage(),
                        null,
                        null,
                        null,
                        null
                    );
                }
            }
        }

        return vectors;
    }

    /**
     * 使用本地服务进行向量化
     */
    private List<float[]> vectorizeWithLocalService(List<String> texts, String modelKey) {
        logger.info("使用本地服务进行向量化");

        List<float[]> vectors = new ArrayList<>();

        for (String text : texts) {
            try {
                VectorizeUtils.VectorizeResult result = VectorizeUtils.vectorize(
                    text, vectorizeBaseUrl, vectorizeApiPath, vectorizeApiKey, vectorizeModel);
                vectors.add(result.getVector());

                recordVectorizeLog(
                    "VECTORIZE_LOCAL",
                    result.getModel() != null ? result.getModel() : modelKey,
                    result.getRequestUrl(),
                    result.getRequestPayload(),
                    result.getResponsePayload(),
                    result.getDurationMs(),
                    true,
                    null,
                    result.getApiKey(),
                    result.getPromptTokens(),
                    result.getCompletionTokens(),
                    result.getTotalTokens()
                );
            } catch (Exception e) {
                logger.error("本地服务向量化单文本失败: {}", text.substring(0, Math.min(100, text.length())), e);
                // 添加空向量
                vectors.add(new float[getDimension()]);

                if (e instanceof VectorizeRequestException vex) {
                    recordVectorizeLog(
                        "VECTORIZE_LOCAL",
                        vex.getModel() != null ? vex.getModel() : modelKey,
                        vex.getRequestUrl(),
                        vex.getRequestPayload(),
                        vex.getResponsePayload(),
                        vex.getDurationMs(),
                        false,
                        vex.getMessage(),
                        vex.getApiKey(),
                        null,
                        null,
                        null
                    );
                } else {
                    recordVectorizeLog(
                        "VECTORIZE_LOCAL",
                        modelKey,
                        null,
                        null,
                        null,
                        null,
                        false,
                        e.getMessage(),
                        null,
                        null,
                        null,
                        null
                    );
                }
            }
        }

        return vectors;
    }

    private List<String> normalizeTexts(List<String> texts, LimitSettings limits) {
        List<String> normalized = new ArrayList<>(texts == null ? 0 : texts.size());
        if (texts == null) {
            return normalized;
        }
        for (String text : texts) {
            normalized.add(limitTextLength(text, limits));
        }
        return normalized;
    }

    private String limitTextLength(String rawText, LimitSettings limits) {
        if (rawText == null) {
            return "";
        }
        String trimmed = rawText.trim();
        if (trimmed.isEmpty()) {
            return trimmed;
        }

        if (limits.getMaxChars() > 0) {
            int codePoints = trimmed.codePointCount(0, trimmed.length());
            if (codePoints > limits.getMaxChars()) {
                int endIndex = trimmed.offsetByCodePoints(0, limits.getMaxChars());
                logger.debug("模型 {} 文本超出单次{}字限制，已截断。原始长度: {}", limits.getModelKey(), limits.getMaxChars(), codePoints);
                trimmed = trimmed.substring(0, endIndex);
            }
        }

        if (limits.getMaxTokens() > 0) {
            int tokenCount = estimateTokenCount(trimmed);
            if (tokenCount > limits.getMaxTokens()) {
                int endIndex = trimmed.offsetByCodePoints(0, limits.getMaxTokens());
                logger.debug("模型 {} 文本超出{} token限制，已截断。原始token数: {}", limits.getModelKey(), limits.getMaxTokens(), tokenCount);
                trimmed = trimmed.substring(0, endIndex);
            }
        }

        return trimmed;
    }

    private int estimateTokenCount(String text) {
        if (text == null || text.isEmpty()) {
            return 0;
        }
        return text.codePointCount(0, text.length());
    }

    private LimitSettings resolveLimitSettings() {
        String modelKey = determineModelKey();
        int charLimit = resolveLimitValue(modelKey, "max-chars", defaultMaxChars);
        int tokenLimit = resolveLimitValue(modelKey, "max-tokens", defaultMaxTokens);
        logger.debug("向量化模型 {} 使用阈值: {} 字 / {} token", modelKey, charLimit, tokenLimit);
        return new LimitSettings(modelKey, charLimit, tokenLimit);
    }

    private String determineModelKey() {
        if ("office".equalsIgnoreCase(vectorizationMode)) {
            String officeModel = officeGatewayService.getEmbeddingModel();
            if (officeModel != null && !officeModel.isBlank()) {
                return officeModel;
            }
            return "office";
        }
        if (vectorizeModel != null && !vectorizeModel.isBlank()) {
            return vectorizeModel;
        }
        return "default";
    }

    private int resolveLimitValue(String modelKey, String property, int fallback) {
        String propertyKey = "vector-limits." + modelKey + "." + property;
        Integer value = environment.getProperty(propertyKey, Integer.class);
        if (value == null || value <= 0) {
            return fallback;
        }
        return value;
    }

    private void recordVectorizeLog(String source,
                                    String modelName,
                                    String requestUrl,
                                    String requestPayload,
                                    String responsePayload,
                                    Long durationMs,
                                    boolean success,
                                    String errorMessage,
                                    String apiKey,
                                    Integer promptTokens,
                                    Integer completionTokens,
                                    Integer totalTokens) {
        if (modelRequestLogService == null) {
            return;
        }
        ModelRequestLog logEntry = new ModelRequestLog();
        logEntry.setRequestSource(source);
        logEntry.setRequestUrl(requestUrl);
        logEntry.setRequestMethod("POST");
        logEntry.setModelName(modelName);
        logEntry.setRequestPayload(requestPayload);
        logEntry.setResponsePayload(responsePayload);
        logEntry.setStatus(success ? "SUCCESS" : "FAILED");
        logEntry.setDurationMs(durationMs);
        logEntry.setApiKey(apiKey);
        logEntry.setPromptTokens(promptTokens);
        logEntry.setCompletionTokens(completionTokens);
        logEntry.setTotalTokens(totalTokens);
        logEntry.setErrorMessage(errorMessage);
        modelRequestLogService.record(logEntry);
    }

    private static class LimitSettings {
        private final String modelKey;
        private final int maxChars;
        private final int maxTokens;

        LimitSettings(String modelKey, int maxChars, int maxTokens) {
            this.modelKey = modelKey;
            this.maxChars = maxChars;
            this.maxTokens = maxTokens;
        }

        String getModelKey() {
            return modelKey;
        }

        int getMaxChars() {
            return maxChars;
        }

        int getMaxTokens() {
            return maxTokens;
        }
    }
}
