package cn.com.poc.expose.aggregate.impl;

import cn.com.poc.agent_application.aggregate.AgentApplicationInfoService;
import cn.com.poc.agent_application.constant.AgentApplicationDialoguesRecordConstants;
import cn.com.poc.agent_application.entity.*;
import cn.com.poc.agent_application.service.*;
import cn.com.poc.agent_application.utils.AgentApplicationTools;
import cn.com.poc.common.constant.CommonConstant;
import cn.com.poc.common.service.BosConfigService;
import cn.com.poc.common.utils.DateUtils;
import cn.com.poc.common.utils.UUIDTool;
import cn.com.poc.data_analyze.aggregate.DataAnalyzeReportService;
import cn.com.poc.data_analyze.constants.DataAnalyzeChannelEnum;
import cn.com.poc.equity.aggregate.MemberEquityService;
import cn.com.poc.equity.aggregate.PointDeductionRulesService;
import cn.com.poc.equity.constants.ModifyEventEnum;
import cn.com.poc.equity.domain.modifyEquityInfo.AgentUseModifyEventInfo;
import cn.com.poc.expose.aggregate.AgentApplicationApiService;
import cn.com.poc.knowledge.aggregate.KnowledgeService;
import cn.com.poc.support.security.oauth.constants.OauthConstants;
import cn.com.poc.thirdparty.resource.demand.ai.constants.KnowledgeSearchTypeEnum;
import cn.com.poc.thirdparty.resource.demand.ai.constants.LLMRoleEnum;
import cn.com.poc.thirdparty.resource.demand.ai.entity.dialogue.Message;
import cn.com.poc.thirdparty.resource.demand.ai.entity.dialogue.Tool;
import cn.com.yict.framemax.core.exception.BusinessException;
import cn.com.yict.framemax.security.authentication.SecurityAuthenticationToken;
import cn.com.yict.framemax.security.oauth.OauthUserManager;
import cn.hutool.core.io.FileUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @author alex.yao
 * @date 2024/12/19
 */
@Component
public class AgentApplicationApiServiceImpl implements AgentApplicationApiService {

    @Resource
    private BizAgentApplicationApiProfileService bizAgentApplicationApiProfileService;

    @Resource
    private BizAgentApplicationPublishService bizAgentApplicationPublishService;

    @Resource
    private AgentApplicationInfoService agentApplicationInfoService;

    @Resource
    private KnowledgeService knowledgeService;

    @Resource
    private BizAgentApplicationApiConversationService bizAgentApplicationApiConversationService;

    @Resource
    private PointDeductionRulesService pointDeductionRulesService;

    @Resource
    private MemberEquityService memberEquityService;

    @Resource
    private BizAgentApplicationApiFilesService bizAgentApplicationApiFilesService;

    @Resource
    private BosConfigService bosConfigService;

    @Resource
    private BizAgentApplicationDialoguesRecordService bizAgentApplicationDialoguesRecordService;

    @Resource
    private DataAnalyzeReportService dataAnalyzeReportService;

    @Resource
    private OauthUserManager userManager;

    @Override
    public String conversation(String apiKey, String apiSecret, String agentId) throws Exception {
        BizAgentApplicationApiProfileEntity profileEntity = bizAgentApplicationApiProfileService.getByKeyAndSecret(apiKey, apiSecret);
        if (profileEntity == null) {
            throw new BusinessException("无效的API Key或Secret");
        }
        BizAgentApplicationPublishEntity infoEntity = bizAgentApplicationPublishService.getByAgentId(agentId);
        if (infoEntity == null) {
            throw new BusinessException("无效的Agent ID");
        }
        if (!infoEntity.getMemberId().equals(profileEntity.getMemberId().intValue())) {
            throw new BusinessException("无权限");
        }
        BizAgentApplicationPublishEntity publishEntity = bizAgentApplicationPublishService.getByAgentId(agentId);
        if (null == publishEntity) {
            throw new BusinessException("无效的Agent ID");
        }
        String conversationId = UUID.randomUUID().toString();
        BizAgentApplicationApiConversationEntity bizAgentApplicationApiConversationEntity = new BizAgentApplicationApiConversationEntity();
        bizAgentApplicationApiConversationEntity.setAgentId(agentId);
        bizAgentApplicationApiConversationEntity.setConversationId(conversationId);
        bizAgentApplicationApiConversationEntity.setExpiredTime(DateUtils.addDays(DateUtils.getCurrDateTime(), 7));
        bizAgentApplicationApiConversationService.save(bizAgentApplicationApiConversationEntity);
        return conversationId;
    }

    @Override
    public void completions(String apiKey, String apiSecret, String conversationId, List<String> fileIds, String query, boolean stream, String imageUrl, HttpServletResponse httpServletResponse) throws Exception {
        BizAgentApplicationApiProfileEntity profileEntity = bizAgentApplicationApiProfileService.getByKeyAndSecret(apiKey, apiSecret);
        if (profileEntity == null) {
            throw new BusinessException("无效的API Key或Secret");
        }
        BizAgentApplicationApiConversationEntity conversationEntity = bizAgentApplicationApiConversationService.getByConversationId(conversationId);
        if (null == conversationEntity || DateUtils.getCurrDateTime().after(conversationEntity.getExpiredTime())) {
            throw new BusinessException("无效的对话ID");
        }
        String agentId = conversationEntity.getAgentId();
        BizAgentApplicationPublishEntity infoEntity = bizAgentApplicationPublishService.getByAgentId(agentId);

        if (infoEntity == null) {
            throw new BusinessException("无效的Agent ID");
        }

        if (!infoEntity.getMemberId().equals(profileEntity.getMemberId().intValue())) {
            throw new BusinessException("无权限");
        }
        //配置用户上下文信息
        setAPIUserInfoContext(profileEntity);

        // 获取文件列表
        List<String> fileUrls = getFileUrls(conversationId, fileIds, agentId);

        //获取知识库配置
        List<Integer> kdIdList = knowledgeService.getKdIdsByKnowledgeInfoIds(infoEntity.getKnowledgeIds());
        //知识库超纲问题配置
        KnowledgeSuperclassProblemConfig superclassProblemConfig = new KnowledgeSuperclassProblemConfig();
        superclassProblemConfig.setKnowledgeResponseType(infoEntity.getKnowledgeResponseType());
        superclassProblemConfig.setKnowledgeCustomResponse(infoEntity.getKnowledgeCustomResponse());


        // 构造对话参数
        List<Message> messages = buildMessages(conversationId, agentId, profileEntity.getMemberId(), query);

        //配置对话function
        List<Tool> tools = AgentApplicationTools.buildFunctionConfig(infoEntity.getVariableStructure(), infoEntity.getIsLongMemory(), conversationId, agentId, infoEntity.getUnitIds(), infoEntity.getIsDocumentParsing());

        //获取对话图片
        List<String> imageUrls = AgentApplicationTools.buildImageUrls(imageUrl);

        // 保存用户输入记录
        Long inputTimestamp = System.currentTimeMillis();

        //计算扣分数
        // 判断是否调用function
        CheckPluginUseEntity checkPluginUseEntity = AgentApplicationTools.checkPluginUse(messages, tools, fileUrls, imageUrls);
        Long pointDeductionNum = pointDeductionRulesService.calculatePointDeductionNum(infoEntity.getLargeModel(), infoEntity.getCommunicationTurn(), checkPluginUseEntity.getDeductionTools());
        AgentUseModifyEventInfo agentUseModifyEventInfo = new AgentUseModifyEventInfo();
        agentUseModifyEventInfo.setAgentId(agentId);
        agentUseModifyEventInfo.setIsPublish(CommonConstant.IsDeleted.Y);
        Long deducted = profileEntity.getMemberId();
        String reduceSn = memberEquityService.reducePoint(deducted, pointDeductionNum, ModifyEventEnum.use, agentUseModifyEventInfo);

        //对话
        try {
            AgentResultEntity agentResultEntity = agentApplicationInfoService.callAgentApplication(agentId, conversationId, infoEntity.getLargeModel(),
                    infoEntity.getAgentSystem(), kdIdList.toArray(new Integer[0]), infoEntity.getCommunicationTurn(),
                    infoEntity.getTopP(), infoEntity.getTemperature(), messages, tools, checkPluginUseEntity.getFunctionCallResult(), fileUrls, stream, imageUrls,
                    infoEntity.getKnowledgeSimilarity(), infoEntity.getKnowledgeNResult(), KnowledgeSearchTypeEnum.valueOf(infoEntity.getKnowledgeSearchType()),
                    superclassProblemConfig, httpServletResponse);
            saveRecord(conversationId, query, agentId, profileEntity, inputTimestamp, infoEntity, agentResultEntity.getMessage());
        } catch (Exception e) {
            memberEquityService.rollbackPoint(reduceSn);
        }
        //数据采集
        dataAnalyzeReportService.dataReport(agentId, DataAnalyzeChannelEnum.api, profileEntity.getMemberId(), deducted, pointDeductionNum);
    }

    private void setAPIUserInfoContext(BizAgentApplicationApiProfileEntity profileEntity) {
        SecurityAuthenticationToken securityAuthenticationToken = this.userManager.authUser(OauthConstants.TypePrefix.MEMBER_DOMAIN + profileEntity.getMemberId().toString(), null, null);
        SecurityContext sc = SecurityContextHolder.getContext();
        sc.setAuthentication(securityAuthenticationToken);
        SecurityContextHolder.setContext(sc);
    }

    private void saveRecord(String conversationId, String query, String agentId, BizAgentApplicationApiProfileEntity profileEntity, Long inputTimestamp, BizAgentApplicationPublishEntity infoEntity, String output) throws Exception {
        //保存对话记录
        BizAgentApplicationDialoguesRecordEntity inputRecord = new BizAgentApplicationDialoguesRecordEntity();
        inputRecord.setAgentId(agentId);
        inputRecord.setMemberId(profileEntity.getMemberId());
        inputRecord.setContent(query);
        inputRecord.setDialogsId(conversationId);
        inputRecord.setRole(AgentApplicationDialoguesRecordConstants.ROLE.USER);
        inputRecord.setTimestamp(inputTimestamp);

        BizAgentApplicationDialoguesRecordEntity outputRecord = new BizAgentApplicationDialoguesRecordEntity();
        outputRecord.setRole(AgentApplicationDialoguesRecordConstants.ROLE.ASSISTANT);
        outputRecord.setAgentId(infoEntity.getAgentId());
        outputRecord.setDialogsId(conversationId);
        outputRecord.setMemberId(profileEntity.getMemberId());
        outputRecord.setTimestamp(System.currentTimeMillis());
        outputRecord.setContent(output);
        bizAgentApplicationDialoguesRecordService.save(inputRecord);
        bizAgentApplicationDialoguesRecordService.save(outputRecord);
    }

    @Override
    public String uploadFile(String apiKey, String apiSecret, String agentId, String conversationId, MultipartFile file) throws Exception {
        BizAgentApplicationApiProfileEntity profileEntity = bizAgentApplicationApiProfileService.getByKeyAndSecret(apiKey, apiSecret);
        if (profileEntity == null) {
            throw new BusinessException("无效的API Key或Secret");
        }
        BizAgentApplicationPublishEntity infoEntity = bizAgentApplicationPublishService.getByAgentId(agentId);
        if (infoEntity == null) {
            throw new BusinessException("无效的Agent ID");
        }
        if (!infoEntity.getMemberId().equals(profileEntity.getMemberId().intValue())) {
            throw new BusinessException("无权限");
        }
        BizAgentApplicationPublishEntity publishEntity = bizAgentApplicationPublishService.getByAgentId(agentId);
        if (null == publishEntity) {
            throw new BusinessException("无效的Agent ID");
        }

        if (!checkConversationEffectiveness(conversationId)) {
            throw new BusinessException("无效的对话ID");
        }
        //校验文件类型
        String type = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1, file.getOriginalFilename().length());
        if (!(type.equals("pdf") || type.equals("doc") || type.equals("docx") || type.equals("md") || type.equals("txt"))) {
            throw new BusinessException("文件类型不支持");
        }
        // 文件大小不能超过10M
        long fileSizeInBytes = file.getSize();
        double fileSizeInMB = (double) fileSizeInBytes / (1024 * 1024);
        if (fileSizeInMB > 10) {
            throw new BusinessException("文件不可超过10m");
        }
        File tempFile = File.createTempFile(UUIDTool.getUUID(), "." + type);
        file.transferTo(tempFile);
        BufferedInputStream inputStream = FileUtil.getInputStream(tempFile);
        String uploadUrl = bosConfigService.upload(inputStream, type, file.getContentType());
        tempFile.delete();
        String fileId = UUID.randomUUID().toString();
        BizAgentApplicationApiFilesEntity bizAgentApplicationApiFilesEntity = new BizAgentApplicationApiFilesEntity();
        bizAgentApplicationApiFilesEntity.setAgentId(agentId);
        bizAgentApplicationApiFilesEntity.setConversationId(conversationId);
        bizAgentApplicationApiFilesEntity.setFileId(fileId);
        bizAgentApplicationApiFilesEntity.setFileUrl(uploadUrl);
        bizAgentApplicationApiFilesEntity.setExpiredTime(DateUtils.addDays(DateUtils.getCurrDateTime(), 7));
        bizAgentApplicationApiFilesEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        bizAgentApplicationApiFilesService.save(bizAgentApplicationApiFilesEntity);
        return fileId;
    }


    /**
     * 检查对话有效性
     *
     * @param conversationId
     * @return true 有效，false 无效
     */
    private boolean checkConversationEffectiveness(String conversationId) {
        BizAgentApplicationApiConversationEntity conversationEntity = bizAgentApplicationApiConversationService.getByConversationId(conversationId);
        return null != conversationEntity && !DateUtils.getCurrDateTime().after(conversationEntity.getExpiredTime());
    }

    /**
     * 获取文件地址列表
     *
     * @param conversationId 对话ID
     * @param fileIds        文件ID列表
     * @param agentId        应用ID
     * @return
     * @throws Exception
     */
    private List<String> getFileUrls(String conversationId, List<String> fileIds, String agentId) throws Exception {
        List<String> fileUrls = new ArrayList<>();
        Date currDateTime = DateUtils.getCurrDateTime();

        if (CollectionUtils.isNotEmpty(fileIds)) {
            for (String fileId : fileIds) {
                BizAgentApplicationApiFilesEntity bizAgentApplicationApiFilesEntity = new BizAgentApplicationApiFilesEntity();
                bizAgentApplicationApiFilesEntity.setAgentId(agentId);
                bizAgentApplicationApiFilesEntity.setConversationId(conversationId);
                bizAgentApplicationApiFilesEntity.setFileId(fileId);
                List<BizAgentApplicationApiFilesEntity> filesEntities = bizAgentApplicationApiFilesService.findByExample(bizAgentApplicationApiFilesEntity, null);
                if (CollectionUtils.isEmpty(filesEntities)) {
                    continue;
                }

                BizAgentApplicationApiFilesEntity filesEntity = filesEntities.get(0);
                if (filesEntity.getExpiredTime().after(currDateTime)) {
                    fileUrls.add(filesEntity.getFileUrl());
                }
            }
        }

        return fileUrls;
    }

    private List<Message> buildMessages(String dialogsId, String agentId, Long userId, String input) throws Exception {
        List<Message> messages = new ArrayList<>();
        BizAgentApplicationDialoguesRecordEntity recordEntity = new BizAgentApplicationDialoguesRecordEntity();
        recordEntity.setDialogsId(dialogsId);
        recordEntity.setMemberId(userId);
        recordEntity.setAgentId(agentId);
        List<BizAgentApplicationDialoguesRecordEntity> recordEntities = bizAgentApplicationDialoguesRecordService.findByExample(recordEntity, null);
        if (CollectionUtils.isNotEmpty(recordEntities)) {
            for (BizAgentApplicationDialoguesRecordEntity entity : recordEntities) {
                Message message = new Message();
                message.setContent(entity.getContent());
                message.setRole(entity.getRole());
                messages.add(message);
            }
        }

        //判断最后是否为User，若是则删除。
        if (CollectionUtils.isNotEmpty(messages)) {
            if (LLMRoleEnum.USER.getRole().equals(messages.get(messages.size() - 1).getRole())) {
                Long recordId = recordEntities.get(recordEntities.size() - 1).getId();
                bizAgentApplicationDialoguesRecordService.deletedById(recordId);
                messages.remove(messages.size() - 1);
            }
        }


        // 用户输入
        Message message = new Message();
        message.setContent(input);
        message.setRole(LLMRoleEnum.USER.getRole());
        messages.add(message);
        return messages;
    }
}
