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

import cn.com.poc.common.constant.CommonConstant;
import cn.com.poc.common.utils.BlContext;
import cn.com.poc.common.utils.FileUtils;
import cn.com.poc.common.utils.JsonUtils;
import cn.com.poc.equity.aggregate.MemberEquityService;
import cn.com.poc.equity.domain.MemberEquityInfo;
import cn.com.poc.knowledge.aggregate.KnowledgeService;
import cn.com.poc.knowledge.constant.KnowledgeConstant;
import cn.com.poc.knowledge.convert.BizKnowledgeInfoConvert;
import cn.com.poc.knowledge.convert.KnowledgeDocumentConvert;
import cn.com.poc.knowledge.dto.*;
import cn.com.poc.knowledge.entity.BizKnowledgeDocumentEntity;
import cn.com.poc.knowledge.entity.BizKnowledgeInfoEntity;
import cn.com.poc.knowledge.query.KnowledgeInfosQueryCondition;
import cn.com.poc.knowledge.query.KnowledgeInfosQueryItem;
import cn.com.poc.knowledge.rest.KnowledgeRest;
import cn.com.poc.knowledge.service.BizKnowledgeInfoService;
import cn.com.poc.support.security.oauth.entity.UserBaseEntity;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.GetKnowledgeChunkInfoResult;
import cn.com.yict.framemax.core.i18n.I18nMessageException;
import cn.com.yict.framemax.core.i18n.I18nUtils;
import cn.com.yict.framemax.data.model.PagingInfo;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class KnowledgeRestImpl implements KnowledgeRest {

    @Resource
    private KnowledgeService knowledgeService;

    @Resource
    private BizKnowledgeInfoService bizKnowledgeInfoService;

    @Resource
    private MemberEquityService memberEquityService;

    @Override
    public List<BizKnowledgeDocumentDto> uploadDocument(MultipartFile[] documentFiles, String knowledgeType) throws Exception {
        Assert.notEmpty(documentFiles);
        Assert.isTrue(documentFiles.length <= 5);
        UserBaseEntity userBaseEntity = BlContext.getCurrentUserNotException();
        MemberEquityInfo equityInfo = memberEquityService.getEquityInfo(userBaseEntity.getUserId());
        String lock = userBaseEntity.getUserId().toString().intern();
        synchronized (lock) {
            //次数检查
            Integer knowledgeNum = equityInfo.getKnowledgeNum();
            if ((documentFiles.length + equityInfo.getUsedKnowledgeNum()) > knowledgeNum) {
                throw new I18nMessageException("exception/create.num.limit");
            }
            List<BizKnowledgeDocumentEntity> entities = knowledgeService.uploadDocument(documentFiles, knowledgeType);
            return entities.stream().map(entity -> {
                BizKnowledgeDocumentDto dto = new BizKnowledgeDocumentDto();
                BeanUtil.copyProperties(entity, dto);
                dto.setDocumentSize(FileUtils.formatFileSize(entity.getDocumentSize()));
                return dto;
            }).collect(Collectors.toList());
        }
    }

    @Override
    public Boolean delDocument(Integer knowledgeInfoId, Integer kdId) {
        Assert.notNull(knowledgeInfoId);
        Assert.notNull(kdId);
        return knowledgeService.delDocument(knowledgeInfoId, kdId);
    }

    @Override
    public Boolean batchDelDocument(Integer knowledgeInfoId, List<Integer> kdId) {
        Assert.notEmpty(kdId);
        Assert.notNull(knowledgeInfoId);
        boolean result = true;
        for (Integer id : kdId) {
            result = result && knowledgeService.delDocument(knowledgeInfoId, id);
        }
        return result;
    }

    @Override
    public Boolean renameDocument(Integer kdId, String rename) throws Exception {
        Assert.notNull(kdId);
        Assert.notEmpty(rename);
        return knowledgeService.renameDocument(kdId, rename);
    }

    @Override
    public String enableKnowledge(Integer kdId) throws Exception {
        Assert.notNull(kdId);
        return knowledgeService.enableKnowledge(kdId);
    }

    @Override
    public Boolean trainKnowledge(TrainKnowledgeDto dto) throws Exception {
        Assert.notNull(dto);
        Assert.notNull(dto.getKnowledgeInfoId());
        Assert.notNull(dto.getKdIds());
        Assert.notNull(dto.getSegmentationConfig());
        UserBaseEntity userBaseEntity = BlContext.getCurrentUser();
        MemberEquityInfo equityInfo = memberEquityService.getEquityInfo(userBaseEntity.getUserId());
        String lock = userBaseEntity.getUserId().toString().intern();
        synchronized (lock) {
            if ((dto.getKdIds().size() + equityInfo.getUsedKnowledgeNum()) > equityInfo.getKnowledgeNum()) {
                throw new I18nMessageException("exception/create.num.limit");
            }
            return knowledgeService.trainKnowledge(dto.getKnowledgeInfoId(), dto.getKdIds(), dto.getSegmentationConfig());
        }
    }

    @Override
    public List<BizKnowledgeDocumentDto> searchDocuments(String search, String trainStatus, Integer knowledgeInfoId, PagingInfo pagingInfo) throws Exception {
        Assert.notNull(knowledgeInfoId);
        List<BizKnowledgeDocumentDto> result = new ArrayList<>();
        BizKnowledgeInfoEntity bizKnowledgeInfoEntity = bizKnowledgeInfoService.get(knowledgeInfoId);

        if (bizKnowledgeInfoEntity == null) {
            throw new I18nMessageException("exception/knowledge.base.does.not.exist");
        }
        String kdIds = bizKnowledgeInfoEntity.getKdIds();
        if (StringUtils.isBlank(kdIds)) {
            return result;
        }
        List<Integer> kdIdList = JsonUtils.deSerialize(kdIds, new TypeReference<List<Integer>>() {
        }.getType());
        if (CollectionUtils.isEmpty(kdIdList)) {
            return result;
        }

        UserBaseEntity currentUser = BlContext.getCurrentUserNotException();
        List<BizKnowledgeDocumentEntity> entities = knowledgeService.searchDocuments(search, trainStatus, kdIdList, currentUser.getUserId().toString(), pagingInfo);
        if (CollectionUtils.isNotEmpty(entities)) {
            result = entities.stream().map(entity -> {
                BizKnowledgeDocumentDto dto = new BizKnowledgeDocumentDto();
                BeanUtil.copyProperties(entity, dto);
                dto.setDocumentSize(FileUtils.formatFileSize(entity.getDocumentSize()));
                return dto;
            }).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public List<BizKnowledgeDocumentDto> getKdIdsByKnowledgeInfoId(Integer knowledgeInfoId) throws Exception {
        Assert.notNull(knowledgeInfoId);
        BizKnowledgeInfoEntity bizKnowledgeInfoEntity = bizKnowledgeInfoService.get(knowledgeInfoId);
        if (bizKnowledgeInfoEntity == null) {
            throw new I18nMessageException("exception/knowledge.base.does.not.exist");
        }
        List<BizKnowledgeDocumentDto> res = new ArrayList<>();
        String kdIds = bizKnowledgeInfoEntity.getKdIds();
        if (StringUtils.isNotBlank(kdIds)) {
            List<Integer> kdIdList = JsonUtils.deSerialize(kdIds, new TypeReference<List<Integer>>() {
            }.getType());
            if (CollectionUtils.isEmpty(kdIdList)) {
                return res;
            }
            List<BizKnowledgeDocumentEntity> entities = knowledgeService.getListByKdIds(kdIdList);
            if (CollectionUtils.isNotEmpty(entities)) {
                res = entities.stream().map(entity -> {
                    BizKnowledgeDocumentDto dto = new BizKnowledgeDocumentDto();
                    BeanUtil.copyProperties(entity, dto);
                    dto.setDocumentSize(FileUtils.formatFileSize(entity.getDocumentSize()));
                    return dto;
                }).collect(Collectors.toList());
            }
        }
        return res;
    }

    @Override
    public List<BizKnowledgeDocumentDto> getListByKdIds(List<Integer> kdIds) {
        Assert.notEmpty(kdIds);
        List<BizKnowledgeDocumentDto> res = new ArrayList<>();
        List<BizKnowledgeDocumentEntity> entities = knowledgeService.getListByKdIds(kdIds);
        if (CollectionUtils.isNotEmpty(entities)) {
            res = entities.stream().map(entity -> {
                BizKnowledgeDocumentDto dto = new BizKnowledgeDocumentDto();
                BeanUtil.copyProperties(entity, dto);
                dto.setDocumentSize(FileUtils.formatFileSize(entity.getDocumentSize()));
                return dto;
            }).collect(Collectors.toList());
        }
        return res;
    }

    @Override
    public BizKnowledgeInfoDto getKnowledgeDetail(Integer knowledgeInfoId) throws Exception {
        Assert.notNull(knowledgeInfoId);
        BizKnowledgeInfoEntity bizKnowledgeInfoEntity = bizKnowledgeInfoService.get(knowledgeInfoId);
        return BizKnowledgeInfoConvert.entityToDto(bizKnowledgeInfoEntity);
    }

    @Override
    public List<QueryKnowledgeDocumentDto> getKnowledgeList(String search, String trainStatus, PagingInfo pagingInfo) throws Exception {
        List<QueryKnowledgeDocumentDto> result = new ArrayList<>();
        UserBaseEntity userBaseEntity = BlContext.getCurrentUserNotException();
        KnowledgeInfosQueryCondition condition = new KnowledgeInfosQueryCondition();
        condition.setMemberId(userBaseEntity.getUserId().toString());
        if (StringUtils.isNoneBlank(search)) {
            condition.setQuery(search);
        }
        if (StringUtils.isNoneBlank(trainStatus)) {
            condition.setTrainStatus(trainStatus);
        }
        List<KnowledgeInfosQueryItem> items = bizKnowledgeInfoService.knowledgeInfos(condition, pagingInfo);
        if (CollectionUtils.isNotEmpty(items)) {
            result = items.stream().map(item -> {
                QueryKnowledgeDocumentDto dto = new QueryKnowledgeDocumentDto();
                BeanUtil.copyProperties(item, dto);
                dto.setDesc(item.getKnowledgeDesc());
                List<Integer> kdIdList = JsonUtils.deSerialize(item.getKdIds(), new TypeReference<List<Integer>>() {
                }.getType());
                if (CollectionUtils.isNotEmpty(kdIdList)) {
                    List<BizKnowledgeDocumentEntity> entities = knowledgeService.getListByKdIds(kdIdList);
                    if (CollectionUtils.isNotEmpty(entities)) {
                        dto.setDocumentInfos(entities.stream().map(KnowledgeDocumentConvert::entityToDto).collect(Collectors.toList()));
                    }
                }
                return dto;
            }).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public List<QueryKnowledgeDocumentDto> getKnowledgeListByKnowledgeInfoIds(List<Integer> knowledgeInfoIds) throws Exception {
        Assert.notEmpty(knowledgeInfoIds);
        List<QueryKnowledgeDocumentDto> result = new ArrayList<>();
        for (Integer knowledgeInfoId : knowledgeInfoIds) {
            BizKnowledgeInfoEntity bizKnowledgeInfoEntity = bizKnowledgeInfoService.get(knowledgeInfoId);
            if (bizKnowledgeInfoEntity == null) {
                continue;
            }
            QueryKnowledgeDocumentDto dto = new QueryKnowledgeDocumentDto();
            BeanUtil.copyProperties(bizKnowledgeInfoEntity, dto);
            List<Integer> kdIdList = JsonUtils.deSerialize(bizKnowledgeInfoEntity.getKdIds(), new TypeReference<List<Integer>>() {
            }.getType());
            if (CollectionUtils.isNotEmpty(kdIdList)) {
                List<BizKnowledgeDocumentEntity> entities = knowledgeService.getListByKdIds(kdIdList);
                if (CollectionUtils.isNotEmpty(entities)) {
                    dto.setDocumentInfos(entities.stream().map(KnowledgeDocumentConvert::entityToDto).collect(Collectors.toList()));
                }
            }
            result.add(dto);
        }
        return result;
    }

    @Override
    public BizKnowledgeInfoDto createKnowledge(BizKnowledgeInfoDto dto) throws Exception {
        Assert.notNull(dto.getKnowledgeName(), I18nUtils.message("assert/knowledge.name.null"));
        if (StringUtils.isBlank(dto.getKnowledgeType())) {
            dto.setKnowledgeType(KnowledgeConstant.KnowledgeType.BASE);
        }
        UserBaseEntity userBaseEntity = BlContext.getCurrentUserNotException();
        BizKnowledgeInfoEntity bizKnowledgeInfoEntity = new BizKnowledgeInfoEntity();
        bizKnowledgeInfoEntity.setKnowledgeName(dto.getKnowledgeName());
        bizKnowledgeInfoEntity.setMemberId(userBaseEntity.getUserId().toString());
        bizKnowledgeInfoEntity.setKnowledgeType(dto.getKnowledgeType());
        bizKnowledgeInfoEntity.setTrainStatus(KnowledgeConstant.TrainStatus.UNOPENED);
        bizKnowledgeInfoEntity.setKnowledgeDesc(dto.getDesc());
        BizKnowledgeInfoEntity entity = bizKnowledgeInfoService.save(bizKnowledgeInfoEntity);
        return BizKnowledgeInfoConvert.entityToDto(entity);
    }

    @Override
    public BizKnowledgeInfoDto updateKnowledgeInfo(BizKnowledgeInfoDto dto) throws Exception {
        Assert.notNull(dto.getId());
        Assert.notBlank(dto.getKnowledgeName(), I18nUtils.message("assert/knowledge.name.null"));
        BizKnowledgeInfoEntity bizKnowledgeInfoEntity = new BizKnowledgeInfoEntity();
        bizKnowledgeInfoEntity.setId(dto.getId());
        bizKnowledgeInfoEntity.setKnowledgeName(dto.getKnowledgeName());
        bizKnowledgeInfoEntity.setKnowledgeDesc(dto.getDesc());
        BizKnowledgeInfoEntity entity = bizKnowledgeInfoService.update(bizKnowledgeInfoEntity);
        return BizKnowledgeInfoConvert.entityToDto(entity);
    }

    @Override
    public void enableKnowledgeInfo(Integer knowledgeInfoId, String isOpen) throws Exception {
        Assert.notNull(knowledgeInfoId);
        Assert.notBlank(isOpen);
        Assert.isTrue(isOpen.equals(CommonConstant.IsDeleted.N) || isOpen.equals(CommonConstant.IsDeleted.Y));
        BizKnowledgeInfoEntity bizKnowledgeInfoEntity = new BizKnowledgeInfoEntity();
        bizKnowledgeInfoEntity.setId(knowledgeInfoId);
        bizKnowledgeInfoEntity.setIsOpen(isOpen);
        bizKnowledgeInfoService.update(bizKnowledgeInfoEntity);
    }

    @Override
    public void deleteKnowledgeInfo(Integer knowledgeInfoId) throws Exception {
        Assert.notNull(knowledgeInfoId);
        bizKnowledgeInfoService.deletedById(knowledgeInfoId);
    }

    @Override
    public void openKnowledgeChunk(UpsertChunkInfoDto dto) {
        Assert.notNull(dto.getIsOpen());
        Assert.notNull(dto.getChunkRelationId());
        Assert.notNull(dto.getKdId());
        knowledgeService.openKnowledgeChunk(dto.getKdId(), dto.getChunkRelationId(), dto.getIsOpen());
    }

    @Override
    public void deleteKnowledgeChunk(UpsertChunkInfoDto dto) {
        Assert.notNull(dto.getKdId());
        Assert.notNull(dto.getChunkRelationId());
        knowledgeService.deleteKnowledgeChunk(dto.getKdId(), dto.getChunkRelationId());
    }

    @Override
    public void updateKnowledgeChunkDoc(UpsertChunkInfoDto dto) {
        Assert.notNull(dto.getChunkContent());
        Assert.notNull(dto.getChunkRelationId());
        Assert.notNull(dto.getKdId());
        Assert.isTrue(dto.getChunkContent().length() <= 1200, I18nUtils.message("assert/content.length.cannot.exceed", new Object[]{"1200"}));
        knowledgeService.updateKnowledgeChunkDoc(dto.getKdId(), dto.getChunkRelationId(), dto.getChunkContent());
    }

    @Override
    public void addKnowledgeChunk(UpsertChunkInfoDto dto) {
        Assert.notNull(dto.getChunkContent());
        Assert.notNull(dto.getKdId());
        Assert.notNull(dto.getChunkSort());
        Assert.isTrue(dto.getChunkContent().length() <= 1200, I18nUtils.message("assert/content.length.cannot.exceed", new Object[]{"1200"}));
        knowledgeService.addKnowledgeChunk(dto.getKdId(), dto.getChunkContent(), dto.getChunkSort());
    }

    @Override
    public GetKnowledgeChunkInfoResult getChunks(List<Integer> kdIds, String query, PagingInfo pagingInfo) {
        Assert.notEmpty(kdIds);
        return knowledgeService.getChunkInfo(kdIds, query, pagingInfo);
    }

    private void checkEquity(UserBaseEntity userBaseEntity) throws Exception {
        MemberEquityInfo equityInfo = memberEquityService.getEquityInfo(userBaseEntity.getUserId());
        if (equityInfo.getUsedKnowledgeNum() >= equityInfo.getKnowledgeNum()) {
            throw new I18nMessageException("exception/create.num.limit");
        }
    }

}
