package com.infoepoch.pms.agent.platform.model.application;

import com.infoepoch.pms.agent.platform.model.application.dto.DefaultModelResponse;
import com.infoepoch.pms.agent.platform.model.application.dto.DefaultModelSettingsResponse;
import com.infoepoch.pms.agent.platform.model.application.dto.DefaultModelSummaryResponse;
import com.infoepoch.pms.agent.platform.model.application.dto.UpdateDefaultModelSettingsRequest;
import com.infoepoch.pms.agent.platform.model.domain.AiModelConfig;
import com.infoepoch.pms.agent.platform.model.domain.SystemSettings;
import com.infoepoch.pms.agent.platform.model.domain.irepository.ISystemSettingsRepository;
import com.infoepoch.pms.agent.platform.shared.exception.BusinessException;
import com.infoepoch.pms.agent.platform.shared.response.ResultCode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Optional;

/**
 * 系统设置管理服务。
 * <p>
 * 目前仅管理全局默认模型配置的读写。
 * 全局默认模型用于未指定模型的智能体对话。
 * </p>
 */
@Service
@RequiredArgsConstructor
public class SystemSettingsService {

    /**
     * 默认模型配置 ID 所在的设置项 key。
     */
    private static final String KEY_DEFAULT_MODEL = "default_model_config_id";

    /**
     * 默认向量模型配置 ID 所在的设置项 key。
     */
    private static final String KEY_DEFAULT_EMBEDDING_MODEL = "default_embedding_model_config_id";

    /**
     * 默认重排模型配置 ID 所在的设置项 key。
     */
    private static final String KEY_DEFAULT_RERANK_MODEL = "default_rerank_model_config_id";

    /**
     * 向量模型类型。
     */
    private static final String MODEL_TYPE_EMBEDDING = "EMBEDDING";

    /**
     * 重排模型类型。
     */
    private static final String MODEL_TYPE_RERANK = "RERANK";

    private final ISystemSettingsRepository settingsRepository;
    private final ModelQueryService modelQueryService;

    /**
     * 获取全局默认模型配置。
     * <p>若未设置或配置已被删除，返回所有字段为 null 的响应。</p>
     *
     * @return 默认模型响应（字段可能全为 null）
     */
    @Transactional(readOnly = true)
    public DefaultModelResponse getDefaultModel() {
        String value = settingsRepository.findById(KEY_DEFAULT_MODEL)
                .map(SystemSettings::getValue)
                .orElse(null);

        if (value == null || value.isBlank()) {
            return new DefaultModelResponse(null, null, null, null);
        }

        AiModelConfig config;
        try {
            config = modelQueryService.getModelConfigOrNull(value);
        } catch (BusinessException ex) {
            if (ex.getResultCode() == ResultCode.MODEL_CONFIG_NOT_FOUND) {
                return new DefaultModelResponse(null, null, null, null);
            }
            throw ex;
        }
        if (config == null) {
            return new DefaultModelResponse(null, null, null, null);
        }
        return new DefaultModelResponse(
                config.getId(),
                config.getModelName(),
                config.getDisplayName(),
                config.getProvider() == null ? null : config.getProvider().getName()
        );
    }

    /**
     * 设置全局默认模型配置。
     *
     * @param modelConfigId 模型配置 ID
     * @return 更新后的默认模型响应
     * @throws BusinessException MODEL_CONFIG_NOT_FOUND 若模型配置不存在
     */
    @Transactional
    public DefaultModelResponse setDefaultModel(String modelConfigId) {
        AiModelConfig config = modelQueryService.getModelConfigOrNull(modelConfigId);
        if (!"LLM".equals(config.getModelType())) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    "默认模型仅支持设置为 LLM 类型模型配置");
        }

        SystemSettings setting = new SystemSettings(KEY_DEFAULT_MODEL, String.valueOf(modelConfigId));
        settingsRepository.save(setting);

        return new DefaultModelResponse(
                config.getId(),
                config.getModelName(),
                config.getDisplayName(),
                config.getProvider() == null ? null : config.getProvider().getName()
        );
    }

    /**
     * 获取统一的默认模型设置。
     *
     * @return 默认对话、向量和重排模型设置
     */
    @Transactional(readOnly = true)
    public DefaultModelSettingsResponse getDefaultModelSettings() {
        AiModelConfig defaultModel = resolveOptionalDefaultModelConfig(KEY_DEFAULT_MODEL);
        AiModelConfig defaultEmbeddingModel = resolveTypedActiveModelConfig(
                KEY_DEFAULT_EMBEDDING_MODEL,
                MODEL_TYPE_EMBEDDING,
                "默认向量模型配置"
        );
        AiModelConfig defaultRerankModel = resolveTypedActiveModelConfig(
                KEY_DEFAULT_RERANK_MODEL,
                MODEL_TYPE_RERANK,
                "默认重排模型配置"
        );

        return new DefaultModelSettingsResponse(
                defaultModel == null ? null : defaultModel.getId(),
                defaultEmbeddingModel == null ? null : defaultEmbeddingModel.getId(),
                defaultRerankModel == null ? null : defaultRerankModel.getId(),
                DefaultModelSummaryResponse.from(defaultModel),
                DefaultModelSummaryResponse.from(defaultEmbeddingModel),
                DefaultModelSummaryResponse.from(defaultRerankModel)
        );
    }

    /**
     * 解析模型配置 ID。
     *
     * @param rawValue            设置项原始值
     * @param settingDisplayName  设置项中文名称
     * @return 模型配置 ID
     * @throws BusinessException PARAM_ERROR 若值不是合法 Long
     */
    private String parseModelConfigId(String rawValue, String settingDisplayName) {
        try {
            return rawValue.trim();
        } catch (NumberFormatException exception) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    settingDisplayName + " ID 格式非法: " + rawValue.trim());
        }
    }

    /**
     * 解析指定设置项对应的启用模型配置，并校验模型类型。
     *
     * @param settingKey         设置项 key
     * @param expectedModelType  期望的模型类型
     * @param settingDisplayName 设置项中文名称
     * @return 解析后的模型配置，未设置时返回 {@code null}
     * @throws BusinessException MODEL_CONFIG_NOT_FOUND 若模型配置不存在或已停用
     * @throws BusinessException PARAM_ERROR 若配置值非法或模型类型不匹配
     */
    @Transactional(readOnly = true)
    public AiModelConfig resolveTypedActiveModelConfig(String settingKey, String expectedModelType,
                                                        String settingDisplayName) {
        Optional<String> rawValue = settingsRepository.findById(settingKey)
                .map(SystemSettings::getValue)
                .filter(value -> value != null && !value.isBlank());

        if (rawValue.isEmpty()) {
            return null;
        }

        String configId = parseModelConfigId(rawValue.get(), settingDisplayName);
        AiModelConfig config = modelQueryService.findById(configId)
                .orElseThrow(() -> new BusinessException(ResultCode.MODEL_CONFIG_NOT_FOUND,
                        settingDisplayName + " ID=" + configId + " 不存在或已停用"));

        if (!expectedModelType.equals(config.getModelType())) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    settingDisplayName + " 必须引用类型为 " + expectedModelType + " 的模型配置");
        }
        return config;
    }

    /**
     * 统一更新默认模型设置。
     *
     * @param request 默认模型设置请求
     * @return 更新后的默认模型设置
     */
    @Transactional
    public DefaultModelSettingsResponse updateDefaultModelSettings(UpdateDefaultModelSettingsRequest request) {
        saveDefaultModelSetting(KEY_DEFAULT_MODEL, request.defaultModelConfigId(), null, "默认对话模型配置");
        saveDefaultModelSetting(KEY_DEFAULT_EMBEDDING_MODEL, request.defaultEmbeddingModelConfigId(), MODEL_TYPE_EMBEDDING, "默认向量模型配置");
        saveDefaultModelSetting(KEY_DEFAULT_RERANK_MODEL, request.defaultRerankModelConfigId(), MODEL_TYPE_RERANK, "默认重排模型配置");
        return getDefaultModelSettings();
    }

    /**
     * 清理默认模型设置中对指定模型配置的引用。
     *
     * @param modelConfigIds 待删除的模型配置 ID 集合
     */
    @Transactional
    public void clearDefaultModelReferences(Collection<String> modelConfigIds) {
        if (modelConfigIds == null || modelConfigIds.isEmpty()) {
            return;
        }
        clearDefaultModelReference(KEY_DEFAULT_MODEL, modelConfigIds);
        clearDefaultModelReference(KEY_DEFAULT_EMBEDDING_MODEL, modelConfigIds);
        clearDefaultModelReference(KEY_DEFAULT_RERANK_MODEL, modelConfigIds);
    }

    /**
     * 解析默认对话模型配置。
     *
     * @param settingKey 设置项 key
     * @return 模型配置，未设置或配置不存在时返回 {@code null}
     */
    @Transactional(readOnly = true)
    public AiModelConfig resolveOptionalDefaultModelConfig(String settingKey) {
        Optional<String> rawValue = settingsRepository.findById(settingKey)
                .map(SystemSettings::getValue)
                .filter(value -> value != null && !value.isBlank());

        if (rawValue.isEmpty()) {
            return null;
        }

        String configId = parseModelConfigId(rawValue.get(), "默认对话模型配置");
        return modelQueryService.findById(configId).orElse(null);
    }

    /**
     * 保存默认模型设置项。
     *
     * @param settingKey 设置项 key
     * @param modelConfigId 模型配置 ID
     * @param expectedModelType 期望模型类型，允许为空表示不校验类型
     * @param settingDisplayName 设置项中文名称
     */
    private void saveDefaultModelSetting(String settingKey, String modelConfigId, String expectedModelType,
                                         String settingDisplayName) {
        if (modelConfigId == null) {
            settingsRepository.save(new SystemSettings(settingKey, null));
            return;
        }

        AiModelConfig config = modelQueryService.findById(modelConfigId).orElseThrow(() -> new BusinessException(
                ResultCode.MODEL_CONFIG_NOT_FOUND,
                expectedModelType == null
                        ? settingDisplayName + " ID=" + modelConfigId + " 不存在"
                        : settingDisplayName + " ID=" + modelConfigId + " 不存在或已停用"));

        if (expectedModelType != null && !expectedModelType.equals(config.getModelType())) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    settingDisplayName + " 必须引用类型为 " + expectedModelType + " 的模型配置");
        }

        settingsRepository.save(new SystemSettings(settingKey, String.valueOf(modelConfigId)));
    }

    private void clearDefaultModelReference(String settingKey, Collection<String> modelConfigIds) {
        String currentValue = settingsRepository.findById(settingKey)
                .map(SystemSettings::getValue)
                .filter(value -> value != null && !value.isBlank())
                .orElse(null);
        if (currentValue == null || !modelConfigIds.contains(currentValue.trim())) {
            return;
        }
        settingsRepository.save(new SystemSettings(settingKey, null));
    }
}
