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

import cn.com.poc.agent_application.aggregate.AgentApplicationInfoService;
import cn.com.poc.agent_application.convert.AgentApplicationInfoConvert;
import cn.com.poc.agent_application.convert.BizAgentApplicationPublishConvert;
import cn.com.poc.agent_application.dto.AgentApplicationCreateContinueQuesDto;
import cn.com.poc.agent_application.dto.AgentApplicationInfoSearchDto;
import cn.com.poc.agent_application.dto.BizAgentApplicationPublishDto;
import cn.com.poc.agent_application.entity.BizAgentApplicationApiProfileEntity;
import cn.com.poc.agent_application.entity.BizAgentApplicationDialoguesRecordEntity;
import cn.com.poc.agent_application.entity.BizAgentApplicationPublishEntity;
import cn.com.poc.agent_application.query.*;
import cn.com.poc.agent_application.service.BizAgentApplicationDialoguesRecordService;
import cn.com.poc.agent_application.service.BizAgentApplicationPublishService;
import cn.com.poc.common.constant.CommonConstant;
import cn.com.poc.common.utils.Assert;
import cn.com.poc.common.utils.BlContext;
import cn.com.poc.common.utils.StringUtils;
import cn.com.poc.common.utils.UUIDTool;
import cn.com.poc.equity.aggregate.PointDeductionRulesService;
import cn.com.poc.equity.entity.BizPointDeductionRulesEntity;
import cn.com.poc.expose.aggregate.AgentApplicationService;
import cn.com.poc.expose.dto.*;
import cn.com.poc.expose.rest.AgentApplicationRest;
import cn.com.poc.message.entity.AgentApplicationClickEventMessage;
import cn.com.poc.message.service.AgentApplicationProducerService;
import cn.com.poc.support.security.oauth.entity.UserBaseEntity;
import cn.com.yict.framemax.core.i18n.I18nMessageException;
import cn.com.yict.framemax.data.model.PagingInfo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class AgentApplicationRestImpl implements AgentApplicationRest {

    private Logger logger = LoggerFactory.getLogger(AgentApplicationRest.class);

    @Resource
    private AgentApplicationService agentApplicationService;

    @Resource
    private AgentApplicationInfoService agentApplicationInfoService;

    @Resource
    private BizAgentApplicationPublishService bizAgentApplicationPublishService;

    @Resource
    private BizAgentApplicationDialoguesRecordService bizAgentApplicationDialoguesRecordService;

    @Resource
    private AgentApplicationProducerService agentApplicationProducerService;

    @Resource
    private PointDeductionRulesService pointDeductionRulesService;

    @Override
    public List<String> getRecommendQuestions(HttpServletRequest httpServletRequest) throws Exception {
        UserBaseEntity userBaseEntity = BlContext.getCurrentUserNotException();
        return agentApplicationService.getRecommendQuestions(httpServletRequest.getHeader("x-lang"), userBaseEntity.getUserId());
    }

    @Override
    public List<UserCollectDto> getCollectedApplications(PagingInfo pagingInfo) {
        UserBaseEntity userBaseEntity = BlContext.getCurrentUserNotException();
        if (userBaseEntity == null) {
            throw new I18nMessageException("exception/user.not.login");
        }
        Long memberId = userBaseEntity.getUserId();
        List<MemberCollectQueryItem> collectedApplications = agentApplicationService.getCollectedApplications(memberId, pagingInfo);
        List<UserCollectDto> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(collectedApplications)) {
            for (MemberCollectQueryItem item : collectedApplications) {
                UserCollectDto collectDto = new UserCollectDto();
                collectDto.setAgentId(item.getAgentId());
                collectDto.setAgentTitle(item.getAgentTitle());
                collectDto.setAgentDesc(item.getAgentDesc());
                collectDto.setAgentAvatar(item.getAgentAvatar());
                result.add(collectDto);
            }
        }
        return result;
    }

    @Override
    public String createDialogues(String agentId) {
        if (StringUtils.isNotBlank(agentId)) {
            AgentApplicationClickEventMessage agentApplicationClickEventMessage = new AgentApplicationClickEventMessage();
            agentApplicationClickEventMessage.setAgentId(agentId);
            agentApplicationProducerService.clickEvent(agentApplicationClickEventMessage);
        }
        return "DIA_" + UUIDTool.getUUID();
    }

    @Override
    public void callAgentApplication(AgentApplicationDto dto, HttpServletResponse httpServletResponse) throws IOException {
        Assert.notNull(dto);
        Assert.notBlank(dto.getInput());
        Assert.notNull(dto.getAgentId());
        Assert.notNull(dto.getDialogsId());
        try {
            agentApplicationService.callAgentApplication(dto.getAgentId(), dto.getDialogsId(), dto.getInput(), dto.getFileUrls(), dto.getChannel(), dto.getImageUrl(), httpServletResponse);
        } catch (Exception e) {
            httpServletResponse.setContentType("text/event-stream");
            PrintWriter writer = httpServletResponse.getWriter();
            writer.write("data: {\"code\":-1,\"message\":\"" + e.getMessage() + "\"} \n\n");
            writer.write("data: [DONE]\n\n");
            writer.flush();
        }
    }

    @Override
    public List<SearchAgentApplicationDto> agentApplicationList(AgentApplicationInfoSearchDto dto, PagingInfo pagingInfo) throws Exception {
        PublishAgentApplicationQueryCondition condition = new PublishAgentApplicationQueryCondition();
        if (StringUtils.isNotBlank(dto.getQuery())) {
            condition.setQuery(dto.getQuery());
        }
        List<SearchAgentApplicationDto> result = new ArrayList<>();
        List<PublishAgentApplicationQueryItem> items = bizAgentApplicationPublishService.query(condition, pagingInfo);
        if (CollectionUtils.isNotEmpty(items)) {
            result = items.stream().map(AgentApplicationInfoConvert::itemToSearchDto).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public BizAgentApplicationPublishDto getInfo(String agentId) throws Exception {
        Assert.notBlank(agentId);
        BizAgentApplicationPublishEntity entity = bizAgentApplicationPublishService.getByAgentId(agentId);
        if (entity == null) {
            throw new I18nMessageException("exception/application.does.not.exist");
        }
        return BizAgentApplicationPublishConvert.entityToDto(entity);
    }

    @Override
    public List<SearchAgentApplicationDto> getDefaultList(PagingInfo pagingInfo) throws Exception {
        List<SearchAgentApplicationDto> result = new ArrayList<>();
        BizAgentApplicationPublishEntity publishEntity = new BizAgentApplicationPublishEntity();
        publishEntity.setMemberId(0);
        publishEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        List<BizAgentApplicationPublishEntity> entities = bizAgentApplicationPublishService.findByExample(publishEntity, pagingInfo);
        BizPointDeductionRulesEntity bizPointDeductionRulesEntity = new BizPointDeductionRulesEntity();
        bizPointDeductionRulesEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        if (CollectionUtils.isNotEmpty(entities)) {
            result = entities.stream().map(value -> {
                Long pointDeductionNum = pointDeductionRulesService.calculatePointDeductionNum(value.getLargeModel(), value.getCommunicationTurn(), null);
                SearchAgentApplicationDto searchAgentApplicationDto = new SearchAgentApplicationDto();
                searchAgentApplicationDto.setAgentId(value.getAgentId());
                searchAgentApplicationDto.setAgentTitle(value.getAgentTitle());
                searchAgentApplicationDto.setAgentDesc(value.getAgentDesc());
                searchAgentApplicationDto.setAgentAvatar(value.getAgentAvatar());
                searchAgentApplicationDto.setPublishedTime(value.getModifiedTime());
                searchAgentApplicationDto.setCreator("官方");
                searchAgentApplicationDto.setIsDocumentParsing(value.getIsDocumentParsing());
                if (!ArrayUtils.isEmpty(value.getUnitIds())) {
                    searchAgentApplicationDto.setUnitIds(value.getUnitIds());
                } else {
                    searchAgentApplicationDto.setUnitIds(new String[0]);
                }
                searchAgentApplicationDto.setPoints(new BigDecimal(pointDeductionNum).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
                return searchAgentApplicationDto;
            }).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public void unPublish(String agentId) throws Exception {
        Assert.notBlank(agentId);
        agentApplicationInfoService.unPublish(agentId);
    }

    @Override
    public List<String> createContinueQuestions(AgentApplicationCreateContinueQuesDto dto) throws Exception {
        Assert.notNull(dto.getInput());
        return agentApplicationService.createContinueQuestions(dto.getInput());
    }

    @Override
    public List<UserDialoguesDto> getUserDialogues() throws Exception {
        UserBaseEntity userBaseEntity = BlContext.getCurrentUserNotException();
        if (userBaseEntity == null) {
            throw new I18nMessageException("exception/user.not.login");
        }
        Long userId = userBaseEntity.getUserId();
        List<UserDialoguesDto> result = new ArrayList<>();
        List<MemberDialoguesQueryItem> memberDialoguesQueryItems = bizAgentApplicationDialoguesRecordService.memberDialoguesQuery(userId, null);
        if (CollectionUtils.isNotEmpty(memberDialoguesQueryItems)) {
            result = memberDialoguesQueryItems.stream().map(item -> {
                UserDialoguesDto userDialoguesDto = new UserDialoguesDto();
                userDialoguesDto.setDialogsId(item.getDialogsId());
                userDialoguesDto.setAgentId(item.getAgentId());
                String content = item.getContent().length() > 20 ? item.getContent().substring(0, 20) : item.getContent();
                userDialoguesDto.setContent(content);
                return userDialoguesDto;
            }).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public void closeDialogues(String dialogueId) throws Exception {
        Assert.notBlank(dialogueId);
        BizAgentApplicationDialoguesRecordEntity recordEntity = new BizAgentApplicationDialoguesRecordEntity();
        recordEntity.setDialogsId(dialogueId);
        recordEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        List<BizAgentApplicationDialoguesRecordEntity> entities = bizAgentApplicationDialoguesRecordService.findByExample(recordEntity, null);
        if (CollectionUtils.isNotEmpty(entities)) {
            for (BizAgentApplicationDialoguesRecordEntity entity : entities) {
                bizAgentApplicationDialoguesRecordService.deletedById(entity.getId());
            }
        }
    }

    @Override
    public void batchCloseDialogues(List<String> dialogueIds) {
        bizAgentApplicationDialoguesRecordService.batchDeleteByDialogueId(dialogueIds);
    }

    @Override
    public List<DialoguesContextDto> getDialogueContext(String dialogueId) {
        Assert.notBlank(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());
                        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 null;
    }

    @Override
    public String autoPlayByAgentId(String agentId) {
        Assert.notBlank(agentId);
        UserBaseEntity currentUser = BlContext.getCurrentUser();
        return agentApplicationService.autoPlayByAgentId(currentUser.getUserId(), agentId);
    }

    @Override
    public String enableAutoPlay(String agentId, String autoPlay) {
        Assert.notBlank(agentId);
        Assert.notBlank(autoPlay);
        Assert.isTrue(CommonConstant.YOrN.N.equals(autoPlay) || CommonConstant.YOrN.Y.equals(autoPlay));
        UserBaseEntity currentUser = BlContext.getCurrentUser();
        return agentApplicationService.enableAutoPlay(currentUser.getUserId(), agentId, autoPlay);
    }

    @Override
    public AgentApplicationApiProfileDto getApiProfile() {
        UserBaseEntity userBaseEntity = BlContext.getCurrentUser();
        BizAgentApplicationApiProfileEntity apiProfileEntity = agentApplicationService.getApiProfile(userBaseEntity.getUserId());
        AgentApplicationApiProfileDto result = new AgentApplicationApiProfileDto();
        result.setApiKey(apiProfileEntity.getApiKey());
        result.setApiSecret(apiProfileEntity.getApiSecret());
        return result;
    }

    @Override
    public AgentApplicationApiProfileDto resetApiProfile() throws Exception {
        UserBaseEntity userBaseEntity = BlContext.getCurrentUser();
        BizAgentApplicationApiProfileEntity apiProfileEntity = agentApplicationService.resetApiProfile(userBaseEntity.getUserId());
        AgentApplicationApiProfileDto result = new AgentApplicationApiProfileDto();
        result.setApiKey(apiProfileEntity.getApiKey());
        result.setApiSecret(apiProfileEntity.getApiSecret());
        return result;
    }
}
