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

import com.infoepoch.pms.agent.platform.model.application.dto.CreateProviderRequest;
import com.infoepoch.pms.agent.platform.model.application.dto.ProviderResponse;
import com.infoepoch.pms.agent.platform.model.application.dto.UpdateProviderRequest;
import com.infoepoch.pms.agent.platform.agent.domain.irepository.IAgentRepository;
import com.infoepoch.pms.agent.platform.chatbot.domain.irepository.IChatbotRepository;
import com.infoepoch.pms.agent.platform.model.domain.AiModelConfig;
import com.infoepoch.pms.agent.platform.model.domain.AiModelProvider;
import com.infoepoch.pms.agent.platform.model.domain.ProviderType;
import com.infoepoch.pms.agent.platform.model.domain.irepository.IAiModelConfigRepository;
import com.infoepoch.pms.agent.platform.model.domain.irepository.IAiModelProviderRepository;
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 org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.List;

/**
 * 模型供应商管理服务。
 * <p>
 * 负责 AI 模型供应商的 CRUD 操作，包含名称唯一性校验和 API Key 脱敏返回。
 * </p>
 */
@Service
@RequiredArgsConstructor
public class ModelProviderService {

    private final IAiModelProviderRepository providerRepository;
    private final IAiModelConfigRepository configRepository;
    private final ISystemSettingsRepository systemSettingsRepository;
    private final ModelProvisionService modelProvisionService;
    private final IAgentRepository agentRepository;
    private final IChatbotRepository chatbotRepository;
    private final SystemSettingsService systemSettingsService;

    /**
     * 创建模型供应商。
     *
     * @param req 创建请求 DTO
     * @return 脱敏后的供应商响应
     * @throws BusinessException RESOURCE_ALREADY_EXISTS 若名称已存在
     */
    @Transactional
    public ProviderResponse create(CreateProviderRequest req) {
        if (ProviderType.fromCode(req.getType()) == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "不支持的供应商类型: " + req.getType());
        }
        if (providerRepository.existsByName(req.getName())) {
            throw new BusinessException(ResultCode.RESOURCE_ALREADY_EXISTS,
                    "供应商名称 [" + req.getName() + "] 已存在");
        }
        AiModelProvider provider = new AiModelProvider(
                req.getName(), req.getType(),
                req.getBaseUrl(), req.getApiKey(), req.getCustomHeaders(), req.getDescription());
        return new ProviderResponse(providerRepository.save(provider));
    }

    /**
     * 按 ID 查询供应商。
     *
     * @param id 供应商 ID
     * @return 脱敏后的供应商响应
     * @throws BusinessException PROVIDER_NOT_FOUND 若不存在
     */
    @Transactional(readOnly = true)
    public ProviderResponse findById(String id) {
        return new ProviderResponse(getProviderOrThrow(id));
    }

    /**
     * 查询所有供应商，按创建时间倒序排列。
     *
     * @return 供应商响应列表
     */
    @Transactional(readOnly = true)
    public List<ProviderResponse> listAll() {
        return providerRepository.findAllByOrderByCreatedAtDesc()
                .stream()
                .map(ProviderResponse::new)
                .toList();
    }

    /**
     * 更新供应商信息。
     * <p>请求中 apiKey 为 {@code null} 时不修改原 API Key。</p>
     * <p>供应商配置变更后，会在事务提交后失效该供应商名下全部模型缓存。</p>
     *
     * @param id  供应商 ID
     * @param req 更新请求 DTO
     * @return 脱敏后的供应商响应
     * @throws BusinessException PROVIDER_NOT_FOUND 若不存在；RESOURCE_ALREADY_EXISTS 若名称已被占用
     */
    @Transactional
    public ProviderResponse update(String id, UpdateProviderRequest req) {
        AiModelProvider provider = getProviderOrThrow(id);
        if (providerRepository.existsByNameAndIdNot(req.getName(), id)) {
            throw new BusinessException(ResultCode.RESOURCE_ALREADY_EXISTS,
                    "供应商名称 [" + req.getName() + "] 已存在");
        }
        provider.modify(req.getName(), req.getBaseUrl(), req.getApiKey(),
                req.getCustomHeaders(), req.getDescription());
        evictProviderModelCachesAfterCommit(id);
        return new ProviderResponse(providerRepository.save(provider));
    }

    /**
     * 删除供应商。
     *
     * @param id 供应商 ID
     * @throws BusinessException PROVIDER_NOT_FOUND 若不存在
     */
    @Transactional
    public void delete(String id) {
        AiModelProvider provider = getProviderOrThrow(id);
        List<AiModelConfig> configs = configRepository.findAllByProviderId(id);
        assertConfigsNotReferenced(provider, configs);
        systemSettingsService.clearDefaultModelReferences(configs.stream().map(AiModelConfig::getId).toList());
        configs.forEach(config -> configRepository.delete(config.getId()));
        registerConfigCacheEvictionAfterCommit(configs.stream().map(AiModelConfig::getId).toList());
        providerRepository.delete(provider.getId());
    }

    /**
     * 切换供应商启用/禁用状态。
     *
     * @param id 供应商 ID
     * @return 更新后的供应商响应
     * @throws BusinessException PROVIDER_NOT_FOUND 若不存在
     */
    @Transactional
    public ProviderResponse toggle(String id) {
        AiModelProvider provider = getProviderOrThrow(id);
        provider.toggleActive();
        evictProviderModelCachesAfterCommit(id);
        return new ProviderResponse(providerRepository.save(provider));
    }

    /**
     * 在事务提交后失效指定供应商下的全部模型缓存。
     *
     * @param providerId 供应商 ID
     */
    private void evictProviderModelCachesAfterCommit(String providerId) {
        List<String> configIds = configRepository.findAllByProviderId(providerId)
                .stream()
                .map(AiModelConfig::getId)
                .toList();
        registerConfigCacheEvictionAfterCommit(configIds);
    }

    private void registerConfigCacheEvictionAfterCommit(List<String> configIds) {
        if (configIds.isEmpty()) {
            return;
        }
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            configIds.forEach(modelProvisionService::evict);
            return;
        }
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            /**
             * 事务提交后失效该供应商下的全部模型缓存。
             */
            @Override
            public void afterCommit() {
                configIds.forEach(modelProvisionService::evict);
            }
        });
    }

    /**
     * 按 ID 查询供应商，不存在时抛出业务异常。
     *
     * @param id 供应商 ID
     * @return 供应商实体
     */
    private AiModelProvider getProviderOrThrow(String id) {
        return providerRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ResultCode.PROVIDER_NOT_FOUND,
                        "供应商 ID=" + id + " 不存在"));
    }

    private void assertConfigsNotReferenced(AiModelProvider provider, List<AiModelConfig> configs) {
        for (AiModelConfig config : configs) {
            if (agentRepository.existsByModelConfigId(config.getId())) {
                throw new BusinessException(ResultCode.RESOURCE_IN_USE,
                        "供应商 [" + provider.getName() + "] 下的模型配置 [" + config.getDisplayNameOrDefault()
                                + "] 正被智能体引用，无法删除");
            }
            if (chatbotRepository.existsByModelConfigId(config.getId())) {
                throw new BusinessException(ResultCode.RESOURCE_IN_USE,
                        "供应商 [" + provider.getName() + "] 下的模型配置 [" + config.getDisplayNameOrDefault()
                                + "] 正被聊天机器人引用，无法删除");
            }
        }
    }
}
