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

import cn.com.poc.agent_application.constant.AgentApplicationDialoguesRecordConstants;
import cn.com.poc.agent_application.entity.BizAgentApplicationDialoguesRecordEntity;
import cn.com.poc.agent_application.entity.BizAgentApplicationGcConfigEntity;
import cn.com.poc.agent_application.query.AgentApplicationDialoguesRecordQueryItem;
import cn.com.poc.agent_application.service.BizAgentApplicationDialoguesRecordService;
import cn.com.poc.agent_application.service.BizAgentApplicationGcConfigService;
import cn.com.poc.ai_dialogues.aggregate.AiDialoguesService;
import cn.com.poc.ai_dialogues.constant.AiDialoguesTypeEnum;
import cn.com.poc.ai_dialogues.constant.DialoguesPlatformEnum;
import cn.com.poc.ai_dialogues.dto.AiDialoguesRecordDto;
import cn.com.poc.ai_dialogues.entity.AiDialoguesOptions;
import cn.com.poc.ai_dialogues.entity.BizAiDialogues3rdRelationEntity;
import cn.com.poc.ai_dialogues.entity.BizAiDialoguesEntity;
import cn.com.poc.ai_dialogues.entity.BizAiDialoguesProblemAssociationEntity;
import cn.com.poc.ai_dialogues.query.AiDialoguesQueryCondition;
import cn.com.poc.ai_dialogues.query.AiDialoguesQueryItem;
import cn.com.poc.ai_dialogues.service.BizAiDialogues3rdRelationService;
import cn.com.poc.ai_dialogues.service.BizAiDialoguesGuessYouAskService;
import cn.com.poc.ai_dialogues.service.BizAiDialoguesProblemAssociationService;
import cn.com.poc.ai_dialogues.service.BizAiDialoguesService;
import cn.com.poc.appbuilder.aggregation.AppBuilderService;
import cn.com.poc.appbuilder.model.BizAppbuilderConversationModel;
import cn.com.poc.appbuilder.service.BizAppbuilderConversationService;
import cn.com.poc.common.constant.CommonConstant;
import cn.com.poc.common.constant.XLangConstant;
import cn.com.poc.common.service.BizFileUploadRecordService;
import cn.com.poc.common.service.RedisService;
import cn.com.poc.common.utils.Assert;
import cn.com.poc.common.utils.JsonUtils;
import cn.com.poc.common.utils.SSEUtil;
import cn.com.poc.common.utils.StringUtils;
import cn.com.poc.expose.aggregate.AgentApplicationExposeService;
import cn.com.poc.expose.dto.DialoguesContextDto;
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.ToolFunction;
import cn.com.poc.thirdparty.resource.demand.ai.entity.largemodel.LargeModelDemandResult;
import cn.com.poc.thirdparty.resource.demand.ai.entity.largemodel.LargeModelResponse;
import cn.com.poc.thirdparty.service.LLMService;
import cn.com.yict.framemax.core.exception.BusinessException;
import cn.com.yict.framemax.frame.service.FmxParamConfigService;
import com.baidubce.appbuilder.model.appbuilderclient.AppBuilderClientIterator;
import com.baidubce.appbuilder.model.appbuilderclient.AppBuilderClientResult;
import com.baidubce.appbuilder.model.appbuilderclient.Event;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.security.SecureRandom;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author alex.yao
 * @date 2025/6/19
 */
@Service
public class AiDialoguesServiceImpl implements AiDialoguesService {

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

    @Resource
    private BizAiDialoguesService bizAiDialoguesService;

    @Resource
    private BizFileUploadRecordService bizFileUploadRecordService;

    @Resource
    private BizAgentApplicationDialoguesRecordService bizAgentApplicationDialoguesRecordService;

    @Resource
    private BizAiDialoguesProblemAssociationService bizAiDialoguesProblemAssociationService;

    @Resource
    private LLMService llmService;

    @Resource
    private BizAgentApplicationGcConfigService bizAgentApplicationGcConfigService;

    @Resource
    private RedisService redisService;

    @Resource
    private AppBuilderService appBuilderService;

    @Resource
    private FmxParamConfigService fmxParamConfigService;

    @Resource
    private BizAiDialogues3rdRelationService bizAiDialogues3rdRelationService;

    @Resource
    private BizAppbuilderConversationService bizAppbuilderConversationService;

    @Override
    public String create(AiDialoguesTypeEnum type, Long userId) throws Exception {
        return this.create(type, null, userId);
    }

    @Override
    public String create(AiDialoguesTypeEnum type, String fileUrl, Long userId) throws Exception {

        Map<AiDialoguesTypeEnum, String> appbuilderMap = new HashMap();
        appbuilderMap.put(AiDialoguesTypeEnum.CAR_INSURANCE, "car_insurance_appid");
        appbuilderMap.put(AiDialoguesTypeEnum.CAR_RECOMMEND, "car_recommend_appid");

        if (appbuilderMap.containsKey(type)) {
            String appid = fmxParamConfigService.getParam(appbuilderMap.get(type));
            String relationId = appBuilderService.conversation(appid);
            if (StringUtils.isBlank(relationId)) {
                throw new BusinessException("创建对话失败");
            }
            String dialoguesId = bizAiDialoguesService.create(type.getType(), fileUrl, userId);
            BizAiDialogues3rdRelationEntity bizAiDialogues3rdRelationEntity = new BizAiDialogues3rdRelationEntity();
            bizAiDialogues3rdRelationEntity.setDialoguesId(dialoguesId);
            bizAiDialogues3rdRelationEntity.setPlatform(DialoguesPlatformEnum.AppBuilder.getPlatform());
            bizAiDialogues3rdRelationEntity.setRelationId(relationId);
            bizAiDialogues3rdRelationService.save(bizAiDialogues3rdRelationEntity);

            BizAppbuilderConversationModel bizAppbuilderConversationModel = new BizAppbuilderConversationModel();
            bizAppbuilderConversationModel.setAppId(appid);
            bizAppbuilderConversationModel.setConversationId(relationId);
            bizAppbuilderConversationService.save(bizAppbuilderConversationModel);

            return dialoguesId;
        }
        return bizAiDialoguesService.create(type.getType(), fileUrl, userId);
    }


    @Override
    public AiDialoguesRecordDto dialoguesDetail(String dialoguesId, Long userId) throws Exception {
        logger.info("get ai dialogues detail dialoguesId:{}, userId:{}", dialoguesId, userId);
        BizAiDialoguesEntity bizAiDialoguesEntity = new BizAiDialoguesEntity();
        bizAiDialoguesEntity.setDialoguesId(dialoguesId);
        bizAiDialoguesEntity.setMemberId(userId);
        bizAiDialoguesEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        List<BizAiDialoguesEntity> entities = bizAiDialoguesService.findByExample(bizAiDialoguesEntity, null);
        if (CollectionUtils.isEmpty(entities)) {
            throw new BusinessException("对话不存在");
        }
        BizAiDialoguesEntity entity = entities.get(0);
        AiDialoguesRecordDto dto = new AiDialoguesRecordDto();
        dto.setDialoguesId(entity.getDialoguesId());
        dto.setDialoguesType(entity.getDialoguesType());
        dto.setTitle(entity.getTitle());
        dto.setMemberId(entity.getMemberId());
        if (StringUtils.isNotBlank(entity.getFileUrl())) {
            dto.setFileUrl(entity.getFileUrl());
            dto.setFileName(bizFileUploadRecordService.getFileNameByFileUrl(entity.getFileUrl()));
        }
        dto.setCreatedTime(entity.getCreatedTime());
        return dto;

    }

    @Override
    public List<AiDialoguesRecordDto> getList(List<AiDialoguesTypeEnum> typeEnumList, Long userId) throws Exception {
        logger.info("get ai dialogues list type:{}, userId:{}", JsonUtils.serialize(typeEnumList), userId);
        List<String> typeList = typeEnumList.stream().map(item -> item.getType()).collect(Collectors.toList());
        AiDialoguesQueryCondition condition = new AiDialoguesQueryCondition();
        condition.setDialoguesTypeList(typeList);
        condition.setMemberId(userId);
        condition.setIsDeleted(CommonConstant.IsDeleted.N);
        List<AiDialoguesQueryItem> entities = bizAiDialoguesService.queryAiDialoguesQuery(condition, null);

        List<AiDialoguesRecordDto> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(entities)) {
            result = entities.stream()
                    .filter(entity -> StringUtils.isNotBlank(entity.getTitle()))
                    .map(entity -> {
                        AiDialoguesRecordDto dto = new AiDialoguesRecordDto();
                        dto.setDialoguesId(entity.getDialoguesId());
                        dto.setDialoguesType(entity.getDialoguesType());
                        dto.setTitle(entity.getTitle());
                        dto.setMemberId(entity.getMemberId());
                        if (StringUtils.isNotBlank(entity.getFileUrl())) {
                            dto.setFileUrl(entity.getFileUrl());
                            dto.setFileName(bizFileUploadRecordService.getFileNameByFileUrl(entity.getFileUrl()));
                        }
                        dto.setCreatedTime(entity.getCreatedTime());
                        return dto;
                    })
                    .sorted(Comparator.comparing(AiDialoguesRecordDto::getCreatedTime).reversed())
                    .collect(Collectors.toList());
        }
        logger.debug("get ai dialogues list result:{}", result);
        return result;
    }

    @Override
    public void batchDelete(List<String> dialoguesIds, Long userId) throws Exception {
        logger.info("batchDelete dialoguesIds:{}", dialoguesIds);
        for (String dialoguesId : dialoguesIds) {
            BizAiDialoguesEntity bizAiDialoguesEntity = new BizAiDialoguesEntity();
            bizAiDialoguesEntity.setDialoguesId(dialoguesId);
            bizAiDialoguesEntity.setMemberId(userId);
            bizAiDialoguesEntity.setIsDeleted(CommonConstant.IsDeleted.N);
            List<BizAiDialoguesEntity> entities = bizAiDialoguesService.findByExample(bizAiDialoguesEntity, null);
            if (CollectionUtils.isEmpty(entities)) {
                continue;
            }
            bizAiDialoguesService.deletedById(entities.get(0).getId());
        }
    }

    @Override
    public List<DialoguesContextDto> getDialogueContext(String dialogueId) {
        List<AgentApplicationDialoguesRecordQueryItem> items = bizAgentApplicationDialoguesRecordService.getDialogueRecord(dialogueId, null);
        if (CollectionUtils.isNotEmpty(items)) {
            return items.stream().map(value -> {
                        DialoguesContextDto dto = new DialoguesContextDto();
                        dto.setRole(value.getRole());
                        dto.setAgentId(value.getAgentId());
                        dto.setContent(value.getContent());
                        if (StringUtils.isNotBlank(value.getFunction())) {
                            dto.setFunction(JsonUtils.deSerialize(value.getFunction(), ToolFunction.class));
                        }
                        dto.setReasoningContent(value.getReasoningContent());
                        dto.setImageUrl(value.getImageUrl());
                        dto.setTimestamp(value.getTimestamp());
                        dto.setAgentTitle(value.getAgentTitle());
                        dto.setAgentAvatar(value.getAgentAvatar());
                        return dto;
                    }
            ).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    @Override
    public List<String> questionAssociation(String dialogueId, String question) {
        List<String> res = new ArrayList<>();
        try {
            if (StringUtils.isBlank(question)) {
                logger.warn("question is blank");
                return Collections.emptyList();
            }
            String GC_CONFIG_CODE = "QuestionAssociation";
            BizAgentApplicationGcConfigEntity gcConfigEntity = bizAgentApplicationGcConfigService.getByConfigCode(GC_CONFIG_CODE);
            if (gcConfigEntity == null) {
                logger.error("获取配置失败");
                return Collections.emptyList();
            }
            Message systemMessage = new Message();
            systemMessage.setContent(gcConfigEntity.getConfigSystem());
            systemMessage.setRole(LLMRoleEnum.SYSTEM.getRole());
            systemMessage.setName("QUESTION_ASSOCIATION_GENERATE");

            Message userMessage = new Message();
            userMessage.setContent(question);
            userMessage.setRole(LLMRoleEnum.USER.getRole());

            LargeModelResponse largeModelResponse = new LargeModelResponse();
            largeModelResponse.setModel(gcConfigEntity.getLargeModel());
            largeModelResponse.setMessages(new Message[]{systemMessage, userMessage});
            largeModelResponse.setStream(false);
            LargeModelDemandResult largeModelDemandResult = llmService.chat(largeModelResponse);
            if (largeModelDemandResult == null || StringUtils.isBlank(largeModelDemandResult.getMessage())) {
                logger.error("大模型响应错误");
                return Collections.emptyList();
            }
            String message = largeModelDemandResult.getMessage();
            int start = message.indexOf("[");
            int end = message.indexOf("]");
            String sub = message.substring(start, end + 1);
            res = JsonUtils.deSerialize(sub, new TypeReference<List<String>>() {
            }.getType());
            return res;
        } finally {
            if (CollectionUtils.isNotEmpty(res)) {
                for (String que : res) {
                    BizAiDialoguesProblemAssociationEntity bizAiDialoguesProblemAssociationEntity = new BizAiDialoguesProblemAssociationEntity();
                    bizAiDialoguesProblemAssociationEntity.setQuestion(que);
                    bizAiDialoguesProblemAssociationService.save(bizAiDialoguesProblemAssociationEntity);
                }
            }
        }
    }

    @Resource
    private AgentApplicationExposeService agentApplicationExposeService;

    @Override
    public List<String> guessYouAsk(String type) {
        //
        String redisKey = "AGENT_APPLICATION_RECOMMEND_QUESTIONS:" + XLangConstant.ZH_CN;

        if (!redisService.hasKey(redisKey) || redisService.lGetListSize(redisKey) < 8) {
            agentApplicationExposeService.createRecommendQuestion();
        }

        long size = redisService.lGetListSize(redisKey);

        List<Object> lastRecomendIdSet = null;
        Set<Long> indexSet = new HashSet<>(8);
        SecureRandom secureRandom = new SecureRandom();

        do {
            long id = secureRandom.nextInt((int) size);
            if (CollectionUtils.isNotEmpty(lastRecomendIdSet) && lastRecomendIdSet.stream().anyMatch(v -> String.valueOf(v).equals(String.valueOf(id)))) {
                continue;
            }
            indexSet.add(id);
        } while (indexSet.size() < 8);

        List<String> result = new ArrayList<>(8);
        for (Long index : indexSet) {
            Object str = redisService.lGetIndex(redisKey, index);
            result.add(str.toString());
        }

        return result;
    }

    @Override
    public String call(String dialoguesId, String input, Long userId, AiDialoguesOptions options) throws Exception {
        Assert.notBlank(dialoguesId);
        Assert.notBlank(input);

        BizAiDialoguesEntity bizAiDialoguesEntity = new BizAiDialoguesEntity();
        bizAiDialoguesEntity.setDialoguesId(dialoguesId);
        bizAiDialoguesEntity.setMemberId(userId);
        bizAiDialoguesEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        List<BizAiDialoguesEntity> bizAiDialoguesEntities = bizAiDialoguesService.findByExample(bizAiDialoguesEntity, null);

        if (CollectionUtils.isEmpty(bizAiDialoguesEntities)) {
            throw new BusinessException("对话ID不存在");
        }

        BizAiDialoguesEntity aiDialoguesEntity = bizAiDialoguesEntities.get(0);

        //更新标题
        if (org.apache.commons.lang3.StringUtils.isBlank(aiDialoguesEntity.getTitle())) { // 标题
            aiDialoguesEntity.setTitle(input.substring(0, Math.min(input.length(), 150)));
            aiDialoguesEntity = bizAiDialoguesService.update(aiDialoguesEntity);
        }

        String dialoguesType = aiDialoguesEntity.getDialoguesType();
        SSEUtil sseUtil = new SSEUtil();
        ToolFunction toolFunction = new ToolFunction();
        StringBuilder contentBuilder = new StringBuilder();
        StringBuilder reasoningContentBuilder = new StringBuilder();

        long inputTimeStamp = System.currentTimeMillis();
        try {
            if (dialoguesType.equals(AiDialoguesTypeEnum.CAR_INSURANCE.getType()) || dialoguesType.equals(AiDialoguesTypeEnum.CAR_RECOMMEND.getType())) {//AppBuilder
                BizAiDialogues3rdRelationEntity bizAiDialogues3rdRelationEntity = new BizAiDialogues3rdRelationEntity();
                bizAiDialogues3rdRelationEntity.setDialoguesId(dialoguesId);
                bizAiDialogues3rdRelationEntity.setPlatform(DialoguesPlatformEnum.AppBuilder.getPlatform());
                bizAiDialogues3rdRelationEntity.setIsDeleted(CommonConstant.IsDeleted.N);
                List<BizAiDialogues3rdRelationEntity> relationEntities = bizAiDialogues3rdRelationService.findByExample(bizAiDialogues3rdRelationEntity, null);
                if (CollectionUtils.isEmpty(relationEntities)) {
                    throw new BusinessException("获取会话配置异常");
                }
                AppBuilderClientIterator iterator = appBuilderService.communication(relationEntities.get(0).getRelationId(), input, null, true);
                while (iterator.hasNext()) {
                    AppBuilderClientResult res = iterator.next();
                    LargeModelDemandResult largeModelDemandResult = new LargeModelDemandResult();
                    largeModelDemandResult.setCode("0");
                    if (ArrayUtils.isNotEmpty(res.getEvents())) {
                        Event event = res.getEvents()[0];
                        String eventType = event.getEventType();
                        if ("chatflow".equals(eventType)) {
                            Map<String, Object> detail = event.getDetail();
                            if (detail.containsKey("message")) {
                                String mess = detail.get("message").toString();
                                largeModelDemandResult.setMessage(mess);
                                contentBuilder.append(mess);
                            }
                        }
                    } else if (StringUtils.isNotEmpty(res.getAnswer())) {
                        largeModelDemandResult.setMessage(res.getAnswer());
                        contentBuilder.append(res.getAnswer());
                    }
                    sseUtil.send(JsonUtils.serialize(largeModelDemandResult));
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            sseUtil.completeByError(e.getMessage());
        } finally {
            sseUtil.send("[DONE]");
            sseUtil.complete();
            //保存对话记录
            //用户输入记录
            BizAgentApplicationDialoguesRecordEntity inputRecord = new BizAgentApplicationDialoguesRecordEntity();
            inputRecord.setAgentId(null);
            inputRecord.setMemberId(userId);
            inputRecord.setContent(input);
            inputRecord.setDialogsId(dialoguesId);
            inputRecord.setRole(AgentApplicationDialoguesRecordConstants.ROLE.USER);
            inputRecord.setTimestamp(inputTimeStamp);
            bizAgentApplicationDialoguesRecordService.save(inputRecord);
            //AI输出记录
            BizAgentApplicationDialoguesRecordEntity outputRecord = new BizAgentApplicationDialoguesRecordEntity();
            outputRecord.setRole(AgentApplicationDialoguesRecordConstants.ROLE.ASSISTANT);
            outputRecord.setAgentId(null);
            outputRecord.setDialogsId(dialoguesId);
            outputRecord.setMemberId(userId);
            if (toolFunction != null) {
                outputRecord.setFunction(JsonUtils.serialize(toolFunction));
            }
            outputRecord.setTimestamp(System.currentTimeMillis());
            outputRecord.setContent(contentBuilder.toString());
            outputRecord.setReasoningContent(reasoningContentBuilder.toString());
            bizAgentApplicationDialoguesRecordService.save(outputRecord);
        }
        return contentBuilder.toString();
    }
}
