package com.seer.teach.teacher.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.seer.teach.common.enums.AiScenarioCodeEnum;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.teacher.common.llm.sse.req.Message;
import com.seer.teach.teacher.module.entity.AiApiKeyEntity;
import com.seer.teach.teacher.module.entity.AiModelEntity;
import com.seer.teach.teacher.module.entity.AiModelTaskEntity;
import com.seer.teach.teacher.module.entity.AiScenarioConfigEntity;
import com.seer.teach.teacher.module.entity.AiScenarioEntity;
import com.seer.teach.teacher.service.AiModelCallService;
import com.seer.teach.teacher.service.IAiApiKeyService;
import com.seer.teach.teacher.service.IAiModelService;
import com.seer.teach.teacher.service.IAiModelTaskService;
import com.seer.teach.teacher.service.IAiScenarioConfigService;
import com.seer.teach.teacher.service.IAiScenarioService;
import com.seer.teach.teacher.service.platform.AiPlatformCallService;
import com.seer.teach.teacher.service.platform.AiPlatformCallServiceFactory;
import com.seer.teach.teacher.service.platform.LlmRequest;
import com.seer.teach.teacher.service.platform.LlmResponse;
import com.seer.teach.teacher.service.platform.LlmTaskRequest;
import com.seer.teach.teacher.service.platform.StreamingTextToAudioResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Queue;
import java.util.UUID;

/**
 * AI模型调用服务实现类
 *
 * @author System
 * @since 2025-10-27
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AiModelCallServiceImpl implements AiModelCallService {

    private final IAiScenarioService aiScenarioService;

    private final IAiScenarioConfigService aiScenarioConfigService;

    private final IAiApiKeyService aiApiKeyService;

    private final IAiModelService aiModelService;

    private final IAiModelTaskService aiModelTaskService;

    private final AiPlatformCallServiceFactory platformFactory;

    /**
     * 通用的模型调用方法
     *
     * @param params       业务参数
     * @param scenarioCode 场景code
     * @return 调用结果
     */
    @Override
    public LlmResponse callModel(String scenarioCode, String prompt, Map<String, Object> params, Integer userId) {
        log.info("callModel 调用大模型，参数: {}, 场景code: {}", params, scenarioCode);

        try {
            // 查询场景配置
            AiScenarioConfigEntity aiScenarioConfig = getAiScenarioConfig(scenarioCode);

            AiModelEntity module = aiModelService.getById(aiScenarioConfig.getModuleId());

            AiApiKeyEntity apiKey = getApiKey(aiScenarioConfig, module.getPlatform(), userId);

            if (Objects.isNull(apiKey)) {
                log.warn("callModel 未找到可用的API密钥");
                return null;
            }
            String platform = aiScenarioConfig.getPlatform();
            log.info("callModel 调用大模型{}，平台: {}，API key 名称:{}", module.getModelIdentifier(), platform, apiKey.getKeyName());
            Long startTime = System.currentTimeMillis();
            AiPlatformCallService platformService = platformFactory.getPlatformService(platform);
            if (platformService == null) {
                log.warn("未找到对应的AI平台服务，平台: {}", platform);
                return null;
            }
            LlmRequest request = new LlmRequest();
            request.setModel(module.getModelIdentifier());
            request.setApiKey(apiKey.getApiKey());
            request.setPrompt(prompt);
            request.setMaxInputTokens(module.getMaxInputTokens());
            request.setMaxTokens(module.getMaxTokens());
            if (StringUtils.hasText(module.getUrl())) {
                request.setUrl(module.getUrl());
            } else {
                request.setUrl(apiKey.getUrl());
            }

            Optional<LlmResponse> callResult = platformService.callTextModel(request);
            Long endTime = System.currentTimeMillis();
            if (callResult.isPresent()) {
                saveModelTask(callResult.get(), aiScenarioConfig, apiKey, module, "text_generation", prompt, "success", MapUtil.getStr(params, "taskId"));

                log.info("callModel 调用大模型成功，耗时: {}s,结果：{}", (endTime - startTime) / 1000, callResult.get());
                // 更新使用统计
                updateApiKeyUsageCount(apiKey, callResult.get());
                return callResult.get();
            }
            return null;
        } catch (Exception e) {
            log.error("调用大模型API时发生异常", e);
            return null;
        }
    }

    @Override
    public LlmResponse callModel(String scenarioCode, List<Message> messages, Map<String, Object> params, Integer userId) {
        log.info("调用大模型，参数: {}, 场景code: {}", params, scenarioCode);
        try {
            // 查询场景配置
            AiScenarioConfigEntity aiScenarioConfig = getAiScenarioConfig(scenarioCode);
            AiModelEntity module = aiModelService.getById(aiScenarioConfig.getModuleId());
            AiApiKeyEntity apiKey = getApiKey(aiScenarioConfig, module.getPlatform(), userId);
            if (Objects.isNull(apiKey)) {
                log.warn("未找到可用的API密钥");
                return null;
            }
            String platform = aiScenarioConfig.getPlatform();
            log.info("调用大模型{}，平台: {}，API key 名称:{}", module.getModelIdentifier(), platform, apiKey.getKeyName());
            Long startTime = System.currentTimeMillis();
            AiPlatformCallService platformService = platformFactory.getPlatformService(platform);
            if (platformService == null) {
                log.warn("未找到对应的AI平台服务，平台: {}", platform);
                return null;
            }
            log.info("调用大模型，开始调用");
            LlmRequest request = new LlmRequest();
            request.setModel(module.getModelIdentifier());
            request.setApiKey(apiKey.getApiKey());
            request.setMessages(messages);
            request.setMaxInputTokens(module.getMaxInputTokens());
            request.setMaxTokens(module.getMaxTokens());
            if (StringUtils.hasText(module.getUrl())) {
                request.setUrl(module.getUrl());
            } else {
                request.setUrl(apiKey.getUrl());
            }
            Optional<LlmResponse> callResult = platformService.callTextModel(request);
            Long endTime = System.currentTimeMillis();
            if (callResult.isPresent()) {
                log.info("调用大模型成功，耗时: {}s,结果：{}", (endTime - startTime) / 1000, callResult.get());
                // 更新使用统计
                updateApiKeyUsageCount(apiKey, callResult.get());
                return callResult.get();
            }
            return null;
        } catch (Exception e) {
            log.error("调用大模型API时发生异常", e);
            return null;
        }
    }

    @Override
    public Queue<StreamingTextToAudioResult> asyncCallText2Audio(String scenarioCode, String text, Map<String, Object> params, Integer userId) {
        // 查询场景配置
        AiScenarioConfigEntity aiScenarioConfig = getAiScenarioConfig(scenarioCode);

        AiModelEntity module = aiModelService.getById(aiScenarioConfig.getModuleId());

        AiApiKeyEntity apiKey = getApiKey(aiScenarioConfig, module.getPlatform(), userId);

        if (Objects.isNull(apiKey)) {
            log.warn("未找到可用的API密钥");
            return null;
        }
        String platform = aiScenarioConfig.getPlatform();
        log.info("调用大模型，平台: {}", platform);
        AiPlatformCallService platformService = platformFactory.getPlatformService(platform);
        if (platformService == null) {
            log.warn("未找到对应的AI平台服务，平台: {}", platform);
            return null;
        }
        log.info("调用大模型，开始调用,模型标识符：{}", module.getModelIdentifier());
        LlmRequest request = new LlmRequest();
        request.setModel(module.getModelIdentifier());
        request.setApiKey(apiKey.getApiKey());
        request.setText(text);
        request.setUrl(apiKey.getUrl());
        return platformService.callText2Audio(request);
    }
    
    @Override
    public Flux<ServerSentEvent<StreamingTextToAudioResult>> streamText2Audio(String scenarioCode, String text, Map<String, Object> params, Integer userId) {
        // 查询场景配置
        AiScenarioConfigEntity aiScenarioConfig = getAiScenarioConfig(scenarioCode);

        AiModelEntity module = aiModelService.getById(aiScenarioConfig.getModuleId());

        AiApiKeyEntity apiKey = getApiKey(aiScenarioConfig, module.getPlatform(), userId);

        if (Objects.isNull(apiKey)) {
            log.warn("streamText2Audio 未找到可用的API密钥");
            return Flux.empty();
        }
        String platform = aiScenarioConfig.getPlatform();
        log.info("streamText2Audio 调用大模型，平台: {}", platform);
        AiPlatformCallService platformService = platformFactory.getPlatformService(platform);
        if (platformService == null) {
            log.warn("streamText2Audio 未找到对应的AI平台服务，平台: {}", platform);
            return Flux.empty();
        }
        log.info("streamText2Audio 调用大模型，开始调用,模型标识符：{}", module.getModelIdentifier());
        LlmRequest request = new LlmRequest();
        request.setModel(module.getModelIdentifier());
        request.setApiKey(apiKey.getApiKey());
        request.setText(text);
        request.setUrl(apiKey.getUrl());
        return platformService.streamText2Audio(request);
    }

    private AiScenarioConfigEntity getAiScenarioConfig(String scenarioCode) {
        // 查询场景配置
        LambdaQueryWrapper<AiScenarioEntity> scenarioWrapper = new LambdaQueryWrapper<>();
        scenarioWrapper.eq(AiScenarioEntity::getScenarioCode, scenarioCode);
        AiScenarioEntity aiScenario = aiScenarioService.getOne(scenarioWrapper);
        AssertUtils.notNull(aiScenario, ResultCodeEnum.SCENARIO_NOT_FOUND);
        // 查询场景配置
        LambdaQueryWrapper<AiScenarioConfigEntity> configWrapper = new LambdaQueryWrapper<>();
        configWrapper.eq(AiScenarioConfigEntity::getScenarioId, aiScenario.getId());
        configWrapper.eq(AiScenarioConfigEntity::getEnabled, 1);
        configWrapper.orderByAsc(AiScenarioConfigEntity::getPriority);
        return aiScenarioConfigService.getOne(configWrapper);
    }

    private AiApiKeyEntity getApiKey(AiScenarioConfigEntity aiScenarioConfig, String platform, Integer userId) {
        List<AiApiKeyEntity> aiApiKeyList = aiApiKeyService.list(new LambdaQueryWrapper<>(AiApiKeyEntity.class).eq(AiApiKeyEntity::getPlatform, platform));

        AiApiKeyEntity apiKey = null;
        if (Objects.nonNull(userId)) {
            Optional<AiApiKeyEntity> any = aiApiKeyList.stream().filter(aiApiKey -> Objects.nonNull(aiApiKey.getOwnerId()) && aiApiKey.getOwnerId().equals(userId)).findAny();
            if (any.isPresent()) {
                apiKey = any.get();
            }
        }
        if (Objects.isNull(apiKey)) {
            Optional<AiApiKeyEntity> any = aiApiKeyList.stream().filter(aiApiKey -> Objects.nonNull(aiScenarioConfig.getApiKeyId()) && aiScenarioConfig.getApiKeyId().intValue() == aiApiKey.getId()).findAny();
            if (any.isPresent()) {
                apiKey = any.get();
            }
        }
        if (Objects.isNull(apiKey)) {
            Optional<AiApiKeyEntity> apiKeyOptional = aiApiKeyList.stream().filter(aiApiKey -> Objects.nonNull(aiApiKey.getIsDefault()) && aiApiKey.getIsDefault() == 1).findAny();
            if (apiKeyOptional.isPresent()) {
                apiKey = apiKeyOptional.get();
            }
        }
        return apiKey;
    }

    @Override
    public String asyncCallText2ImageModel(String scenarioCode, String prompt, Map<String, Object> params, Integer userId) {
        try {
            // 查询场景配置
            AiScenarioConfigEntity aiScenarioConfig = getAiScenarioConfig(scenarioCode);

            AiModelEntity module = aiModelService.getById(aiScenarioConfig.getModuleId());

            AiApiKeyEntity apiKey = getApiKey(aiScenarioConfig, module.getPlatform(), userId);

            if (Objects.isNull(apiKey)) {
                log.warn("未找到可用的API密钥");
                return null;
            }
            String platform = aiScenarioConfig.getPlatform();
            log.info("调用大模型，平台: {}", platform);
            AiPlatformCallService platformService = platformFactory.getPlatformService(platform);
            if (platformService == null) {
                log.warn("未找到对应的AI平台服务，平台: {}", platform);
                return null;
            }
            log.info("调用大模型，开始调用,模型标识符：{}", module.getModelIdentifier());

            LlmRequest request = new LlmRequest();
            request.setModel(module.getModelIdentifier());
            request.setApiKey(apiKey.getApiKey());
            request.setPrompt(prompt);
            request.setN(MapUtil.getInt(params, "imgCount", 1));
            if (StringUtils.hasText(module.getUrl())) {
                request.setUrl(module.getUrl());
            } else {
                request.setUrl(apiKey.getUrl());
            }
            if (AiScenarioCodeEnum.KNOWLEDGE_POINT_GENERATE_IMAGES.getCode().equalsIgnoreCase(scenarioCode)) {
                Optional<String> callResult = platformService.asyncCallImageModel(request);
                if (callResult.isPresent()) {
                    // 保存任务ID到数据库
                    saveModelTask(callResult.get(), aiScenarioConfig, apiKey, module, "image_generation", prompt, "processing");
                    // 更新API Key的图片使用次数
                    updateApiKeyImageUsageCount(apiKey);
                    return callResult.get();
                }
            }
            return null;
        } catch (Exception e) {
            log.error("调用大模型API时发生异常", e);
            return null;
        }
    }

    /**
     * 保存模型任务记录
     *
     * @param llmResponse 响应结果
     * @param config      场景配置
     * @param apiKey      API密钥
     * @param module      模型
     * @param taskType    任务类型
     * @param prompt      提示词
     */
    private void saveModelTask(LlmResponse llmResponse, AiScenarioConfigEntity config, AiApiKeyEntity apiKey,
                               AiModelEntity module, String taskType, String prompt, String status, String taskId) {
        try {
            AiModelTaskEntity taskEntity = new AiModelTaskEntity();
            taskEntity.setTaskId(StringUtils.hasText(taskId) ? taskId : UUID.randomUUID().toString());
            taskEntity.setScenarioConfigId(Long.valueOf(config.getId()));
            taskEntity.setApiKeyId(Long.valueOf(apiKey.getId()));
            taskEntity.setModuleId(Long.valueOf(module.getId()));
            taskEntity.setTaskType(taskType);
            taskEntity.setStatus(status);
            taskEntity.setPrompt(prompt);
            taskEntity.setTaskCreatedTime(LocalDateTime.now());
            taskEntity.setTaskCompletedTime(LocalDateTime.now());
            taskEntity.setOutput(JSONUtil.toJsonStr(llmResponse));
            aiModelTaskService.save(taskEntity);
            log.info("保存AI模型任务记录成功，ID: {}", taskEntity.getId());
        } catch (Exception e) {
            log.error("保存AI模型任务记录失败", e);
        }
    }

    private void saveModelTask(String taskId, AiScenarioConfigEntity config, AiApiKeyEntity apiKey,
                               AiModelEntity module, String taskType, String prompt, String status) {
        try {
            AiModelTaskEntity taskEntity = new AiModelTaskEntity();
            taskEntity.setTaskId(taskId);
            taskEntity.setScenarioConfigId(Long.valueOf(config.getId()));
            taskEntity.setApiKeyId(Long.valueOf(apiKey.getId()));
            taskEntity.setModuleId(Long.valueOf(module.getId()));
            taskEntity.setTaskType(taskType);
            taskEntity.setStatus(status);
            taskEntity.setPrompt(prompt);
            taskEntity.setTaskCreatedTime(LocalDateTime.now());
            aiModelTaskService.save(taskEntity);
            log.info("保存AI模型任务记录成功，任务ID: {}", taskId);
        } catch (Exception e) {
            log.error("保存AI模型任务记录失败，任务ID: {}", taskId, e);
        }
    }

    /**
     * 更新API Key使用次数
     *
     * @param apiKey   API密钥实体
     * @param response 响应体
     */
    private void updateApiKeyUsageCount(AiApiKeyEntity apiKey, LlmResponse response) {
        if (apiKey == null) {
            return;
        }
        try {
            LlmResponse.Usage usage = response.getUsage();
            if (usage != null) {
                AiApiKeyEntity updateEntity = new AiApiKeyEntity();
                updateEntity.setId(apiKey.getId());
                Integer imageCount = usage.getImageCount();
                if (Objects.nonNull(imageCount)) {
                    updateEntity.setUsedImgCount(apiKey.getUsedImgCount() != null ? apiKey.getUsedImgCount() + imageCount : imageCount);
                }
                Integer promptTokens = usage.getPromptTokens();
                Integer completionTokens = usage.getCompletionTokens();
                if (Objects.nonNull(promptTokens) && Objects.nonNull(completionTokens)) {
                    log.info("使用提示词token数: {}", promptTokens);
                    Integer totalTokens = promptTokens + completionTokens;
                    log.info("使用总token数: {}", totalTokens);
                    updateEntity.setUsedTokenCount(apiKey.getUsedTokenCount() != null ? apiKey.getUsedTokenCount() + totalTokens : totalTokens);
                }
                updateEntity.setLastUsed(LocalDateTime.now());
                aiApiKeyService.updateById(updateEntity);
                log.info("更新API Key使用次数成功，API Key ID: {}", apiKey.getId());
            }
        } catch (Exception e) {
            log.error("更新API Key使用次数失败，API Key ID: {}", apiKey.getId(), e);
        }
    }

    @Override
    public List<String> getTaskResult(String taskId) {
        try {
            // 根据任务ID查询任务记录
            LambdaQueryWrapper<AiModelTaskEntity> taskWrapper = new LambdaQueryWrapper<>();
            taskWrapper.eq(AiModelTaskEntity::getTaskId, taskId);
            AiModelTaskEntity taskEntity = aiModelTaskService.getOne(taskWrapper);

            if (taskEntity == null) {
                log.warn("未找到对应的任务记录，任务ID: {}", taskId);
                return Collections.emptyList();
            }

            // 查询API密钥信息
            AiApiKeyEntity apiKey = aiApiKeyService.getById(taskEntity.getApiKeyId());
            if (apiKey == null) {
                log.warn("未找到对应的API密钥，密钥ID: {}", taskEntity.getApiKeyId());
                return Collections.emptyList();
            }

            // 获取平台服务
            AiPlatformCallService platformService = platformFactory.getPlatformService(apiKey.getPlatform());
            if (platformService == null) {
                log.warn("未找到对应的AI平台服务，平台: {}", apiKey.getPlatform());
                return Collections.emptyList();
            }

            LlmTaskRequest taskRequest = new LlmTaskRequest();
            taskRequest.setTaskId(taskId);
            taskRequest.setApiKey(apiKey.getApiKey());
            Optional<LlmResponse> result = platformService.getTaskResult(taskRequest);
            if (result.isPresent()) {
                // 更新任务状态
                updateTaskStatus(taskEntity, result.get());

                // 解析并返回结果
                return parseTaskResult(result.get());
            } else {
                log.warn("获取任务结果为空，任务ID: {}", taskId);
                return Collections.emptyList();
            }
        } catch (Exception e) {
            log.error("获取任务结果时发生异常，任务ID: {}", taskId, e);
            return Collections.emptyList();
        }
    }

    /**
     * 更新任务状态
     *
     * @param taskEntity 任务实体
     * @param result     任务结果
     */
    private void updateTaskStatus(AiModelTaskEntity taskEntity, Object result) {
        try {
            // 更新任务状态
            AiModelTaskEntity updateEntity = new AiModelTaskEntity();
            updateEntity.setId(taskEntity.getId());
            updateEntity.setStatus("success");
            updateEntity.setTaskCompletedTime(LocalDateTime.now());
            updateEntity.setOutput(JSONUtil.toJsonStr(result));
            aiModelTaskService.updateById(updateEntity);
            log.info("更新任务状态成功，任务ID: {}", taskEntity.getTaskId());

        } catch (Exception e) {
            log.error("更新任务状态时发生异常，任务ID: {}", taskEntity.getTaskId(), e);
        }
    }

    /**
     * 解析任务结果
     *
     * @param result 任务结果对象
     * @return 图片URL列表
     */
    private List<String> parseTaskResult(LlmResponse result) {
        try {
            List<String> imageUrls = new ArrayList<>();
            List<LlmResponse.Choice> choices = result.getChoices();
            for (LlmResponse.Choice choice : choices) {
                List<LlmResponse.ImageResult> imageResults = choice.getImageResults();
                for (LlmResponse.ImageResult imageResult : imageResults) {
                    imageUrls.add(imageResult.getUrl());
                }
            }
            return imageUrls;
        } catch (Exception e) {
            log.error("解析任务结果时发生异常", e);
            return Collections.emptyList();
        }
    }

    /**
     * 更新API Key图片使用次数
     *
     * @param apiKey API密钥实体
     */
    private void updateApiKeyImageUsageCount(AiApiKeyEntity apiKey) {
        if (apiKey == null) {
            return;
        }

        try {
            // 更新API Key的图片使用次数
            AiApiKeyEntity updateEntity = new AiApiKeyEntity();
            updateEntity.setId(apiKey.getId());
            updateEntity.setUsedImgCount(apiKey.getUsedImgCount() != null ? apiKey.getUsedImgCount() + 1 : 1);
            updateEntity.setLastUsed(LocalDateTime.now());
            aiApiKeyService.updateById(updateEntity);
            log.info("更新API Key图片使用次数成功，API Key ID: {}", apiKey.getId());
        } catch (Exception e) {
            log.error("更新API Key图片使用次数失败，API Key ID: {}", apiKey.getId(), e);
        }
    }
}