package com.gic.haoban.manage.service.service.contact.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.gic.api.base.commons.BasePageInfo;
import com.gic.api.base.commons.Page;
import com.gic.api.base.commons.ServiceResponse;
import com.gic.clerk.api.dto.ClerkDTO;
import com.gic.clerk.api.service.ClerkService;
import com.gic.commons.util.EntityUtil;
import com.gic.commons.util.GICMQClientUtil;
import com.gic.commons.util.UniqueIdUtils;
import com.gic.haoban.manage.api.dto.contact.ContactFollowDTO;
import com.gic.haoban.manage.api.dto.contact.ContactFollowGoodsDTO;
import com.gic.haoban.manage.api.enums.contact.ContactFollowTypeEnum;
import com.gic.haoban.manage.api.qdto.contact.ContactFollowQDTO;
import com.gic.haoban.manage.api.qdto.contact.ContactFollowSearchQDTO;
import com.gic.haoban.manage.api.qdto.contact.ContactLogQDTO;
import com.gic.haoban.manage.service.dao.mapper.contact.TabContactFollowMapper;
import com.gic.haoban.manage.service.entity.contact.TabContactFollow;
import com.gic.haoban.manage.service.pojo.bo.contact.listFollowCheckBO;
import com.gic.haoban.manage.service.service.contact.ContactFollowService;
import com.gic.marketing.api.dto.member.MemberSmsLogDTO;
import com.gic.marketing.api.service.SmsService;
import com.gic.marketing.pro.api.dto.ai.AiMemberLogListDTO;
import com.gic.marketing.pro.api.service.ai.AiMemberLogApiService;
import com.gic.mq.sdk.GicMQClient;
import com.gic.store.goods.service.StoreGoodsService;
import com.gic.store.goods.vo.StoreGoodsVO;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service("contactFollowService")
public class ContactFollowServiceImpl implements ContactFollowService {

    private static final Logger logger = LogManager.getLogger(ContactFollowService.class);

    private static final List<Integer> aiThirdStatus = Lists.newArrayList(0, 1, 6, 8);

    @Autowired
    private TabContactFollowMapper contactFollowMapper;
    @Autowired
    private StoreGoodsService storeGoodsService;
    @Autowired
    private ClerkService clerkService;
    @Autowired
    private AiMemberLogApiService aiMemberLogApiService;
    @Autowired
    private SmsService smsService;

    @Override
    public void saveFollow(ContactFollowQDTO qdto) {
        saveBatchFollow(Lists.newArrayList(qdto));
    }

    @Override
    public void saveBatchFollow(List<ContactFollowQDTO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        Set<String> clerkSet = list.stream().map(ContactFollowQDTO::getClerkId).collect(Collectors.toSet());
        List<ClerkDTO> clerks = clerkService.getClerkByClerkIds(clerkSet);
        if (CollectionUtils.isEmpty(clerks)) {
            return;
        }
        String enterpriseId = list.get(0).getEnterpriseId();
        Map<String, ClerkDTO> clerkMap = clerks.stream().collect(Collectors.toMap(ClerkDTO::getClerkId, Function.identity(), (v1, v2) -> v1));
        List<TabContactFollow> followList = list.stream().map(follow -> {
            TabContactFollow contactFollow = EntityUtil.changeEntityNew(TabContactFollow.class, follow);
            ClerkDTO clerkDTO = clerkMap.get(follow.getClerkId());
            if (clerkDTO == null) {
                return null;
            }
            contactFollow.setClerkCode(clerkDTO.getClerkCode());
            contactFollow.setFollowId(UniqueIdUtils.uniqueLong());
            if (CollectionUtils.isNotEmpty(follow.getFollowMaterialList())) {
                contactFollow.setFollowMaterial(JSON.toJSONString(follow.getFollowMaterialList()));
            }
            if (CollectionUtils.isNotEmpty(follow.getGoodsInfoList())) {
                contactFollow.setGoodsInfo(JSON.toJSONString(follow.getGoodsInfoList()));
            }
            // 兼容不传followType的老版本
            Integer followTypeOld = contactFollow.getFollowType();
            if (followTypeOld == null) {
                ContactFollowTypeEnum followTypeEnum = ContactFollowTypeEnum.fromTextMatch(contactFollow.getFollowRemark());
                followTypeOld = Optional.ofNullable(followTypeEnum).map(ContactFollowTypeEnum::getCode).orElse(ContactFollowTypeEnum.CONTACT.getCode());
                contactFollow.setFollowType(followTypeOld);
            }
            return contactFollow;
        }).filter(Objects::nonNull).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(followList)) {
            return;
        }
        Integer followType = followList.get(0).getFollowType();
        logger.info("跟进类型:{}", followType);
        // 解决企微群发重复调用问题
        if (Objects.equals(followType, ContactFollowTypeEnum.WECHAT_GROUP_SEND.getCode())) {
            logger.info("企微群发重复调用校验");
            List<listFollowCheckBO> checkList = followList.stream().map(x -> new listFollowCheckBO(x.getMemberId(), x.getClerkId(), x.getFollowTime())).collect(Collectors.toList());
            List<String> checkMemberIdList = contactFollowMapper.listFollowCheck(enterpriseId, checkList);
            logger.info("企微群发重复调用:{}",JSON.toJSONString(checkMemberIdList));
            if (CollectionUtils.isNotEmpty(checkMemberIdList)) {
                followList = followList.stream().filter(x -> !checkMemberIdList.contains(x.getMemberId())).collect(Collectors.toList());
            }
        }
        if (CollectionUtils.isEmpty(followList)) {
            return;
        }
        contactFollowMapper.insertBatch(followList);
        // 部分跟进发送自动建联
        autoContactSend(followList);
    }

    private void autoContactSend(List<TabContactFollow> followList) {
        // 自动建联
        Integer followType = followList.get(0).getFollowType();
        Integer contactAutoType = ContactFollowTypeEnum.fromCode(followType).getContactAutoType();
        if (contactAutoType != null) {
            List<String> message = followList.stream().map(x -> {
                ContactLogQDTO contactLogQDTO = new ContactLogQDTO();
                contactLogQDTO.setMemberId(x.getMemberId());
                contactLogQDTO.setClerkId(x.getClerkId());
                contactLogQDTO.setEnterpriseId(x.getEnterpriseId());
                contactLogQDTO.setContactAutoType(contactAutoType);
                contactLogQDTO.setBizType(x.getSourceType());
                contactLogQDTO.setSourceType(x.getSourceType());
                return JSON.toJSONString(contactLogQDTO);
            }).collect(Collectors.toList());
            String routerName = "autoContactLogForMQ";
            try {
                GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
                clientInstance.sendBatchMessages(routerName, message);
            } catch (Exception e) {
                logger.error("发送错误！路由规则名称：" + routerName + ",message:" + message,e);
            }
            message.clear();
        }
    }

    @Override
    public Page<ContactFollowDTO> pageFollow(String enterpriseId, ContactFollowSearchQDTO searchQDTO, BasePageInfo pageInfo) {
        List<ContactFollowDTO> list = queryMarketingFollowLog(enterpriseId, searchQDTO, pageInfo);
        Page<ContactFollowDTO> page = new Page<>();
        if (list == null || list.isEmpty()) {
            page.setCurrentPage(pageInfo.getPageNum());
            page.setPageSize(pageInfo.getPageSize());
            page.setTotalCount(0);
            page.setTotalPage(1);
            page.setResult(Collections.emptyList());
            return page;
        }
        int totalCount = 500;
        int pageSize = pageInfo.getPageSize();
        int pageNum = pageInfo.getPageNum();
        int totalPage = (int) Math.ceil((double) totalCount / pageSize);

        int fromIndex = Math.max((pageNum - 1) * pageSize, 0);
        fromIndex = Math.min(fromIndex, list.size());
        int toIndex = Math.min(fromIndex + pageSize, totalCount);
        toIndex = Math.min(toIndex, list.size());

        List<ContactFollowDTO> pageList = list.subList(fromIndex, toIndex);

        page.setCurrentPage(pageNum);
        page.setPageSize(pageSize);
        page.setTotalCount(totalCount);
        page.setTotalPage(totalPage);
        page.setResult(pageList);
        return page;
    }

    private List<ContactFollowDTO> queryMarketingFollowLog(String enterpriseId, ContactFollowSearchQDTO searchQDTO, BasePageInfo pageInfo) {
        List<ContactFollowDTO> list = new ArrayList<>();
        ContactFollowDTO followDTO = null;
        Integer maxSize = 500;
        int sizeTotal = pageInfo.getPageNum() * pageInfo.getPageSize();
        sizeTotal = Math.min(sizeTotal, maxSize);
        String memberId = searchQDTO.getMemberId();
        Date date = DateUtil.date();
        DateTime startTime = DateUtil.offsetMonth(date, -6);
        BasePageInfo basePage = new BasePageInfo();
        basePage.setPageNum(1);
        basePage.setPageSize(sizeTotal);
        ServiceResponse<Page<AiMemberLogListDTO>> aiRes = aiMemberLogApiService.pageAiMemberMarketingLog(memberId, "", aiThirdStatus,
                DateUtil.formatDate(startTime), DateUtil.formatDate(date), new HashMap<>(), basePage);
        if (aiRes != null && aiRes.getResult() != null && CollectionUtils.isNotEmpty(aiRes.getResult().getResult())) {
            convertAiFollow(enterpriseId, aiRes.getResult().getResult(), list);
        }
        Page<MemberSmsLogDTO> smsPage = new Page<>();
        smsPage.setCurrentPage(1);
        smsPage.setPageSize(sizeTotal);
        Page<MemberSmsLogDTO> smsRes = smsService.memberSmsLogPage(enterpriseId, memberId, null, DateUtil.beginOfDay(startTime).toJdkDate(), DateUtil.endOfDay(date).toJdkDate(), smsPage);
        if (smsRes != null && CollectionUtils.isNotEmpty(smsRes.getResult())) {
            convertSmsFollow(enterpriseId, smsRes.getResult(), list);
        }
        PageHelper.startPage(basePage);
        List<TabContactFollow> followList = contactFollowMapper.pageFollow(enterpriseId, searchQDTO);
        if (CollectionUtils.isNotEmpty(followList)) {
            List<ContactFollowDTO> pageList = convertExtInfo(followList);
            list.addAll(pageList);
        }
        if (CollectionUtils.isNotEmpty(list)) {
            list = list.stream().sorted(
                            Comparator.comparing(ContactFollowDTO::getFollowTime, Comparator.nullsLast(Comparator.reverseOrder()))
                                    .thenComparing(ContactFollowDTO::getFollowType, Comparator.nullsLast(Comparator.naturalOrder()))
                                    .thenComparing(ContactFollowDTO::getClerkId, Comparator.nullsLast(Comparator.naturalOrder())))
                    .limit(maxSize)
                    .collect(Collectors.toList());
        }
        return list;
    }

    private void convertAiFollow(String enterpriseId, List<AiMemberLogListDTO> aiList, List<ContactFollowDTO> list) {
        if (CollectionUtils.isEmpty(aiList)) {
            return;
        }
        ContactFollowDTO followDTO;
        for (AiMemberLogListDTO aiMemberLog : aiList) {
            followDTO = new ContactFollowDTO();
            followDTO.setMemberId(aiMemberLog.getMemberId());
            followDTO.setFollowType(ContactFollowTypeEnum.AI.getCode());
            followDTO.setFollowRemark(ContactFollowTypeEnum.AI.getTextMatch());
            followDTO.setFollowTime(aiMemberLog.getAiTime());
            followDTO.setEnterpriseId(enterpriseId);
            list.add(followDTO);
        }
    }

    private void convertSmsFollow(String enterpriseId, List<MemberSmsLogDTO> smsList, List<ContactFollowDTO> list) {
        if (CollectionUtils.isEmpty(smsList)) {
            return;
        }
        ContactFollowDTO followDTO;
        for (MemberSmsLogDTO smsLog : smsList) {
            followDTO = new ContactFollowDTO();
            followDTO.setMemberId(smsLog.getMemberId());
            followDTO.setFollowType(ContactFollowTypeEnum.SMS.getCode());
            followDTO.setFollowRemark(ContactFollowTypeEnum.SMS.getTextMatch());
            followDTO.setFollowTime(smsLog.getCreateDate());
            followDTO.setEnterpriseId(enterpriseId);
            list.add(followDTO);
        }
    }

    @Override
    public Map<String, ContactFollowDTO> mapMemberLastFollow(String enterpriseId, String clerkId,List<String> memberIdList) {
        if (CollectionUtils.isEmpty(memberIdList)) {
            return new HashMap<>();
        }
        Date date = DateUtil.date();
        DateTime startTime = DateUtil.offsetMonth(date, -6);
        List<TabContactFollow> list = contactFollowMapper.lastFollowByMemberId(enterpriseId, clerkId, memberIdList);
        List<ContactFollowDTO> followDTOList = convertExtInfo(list);

        ServiceResponse<List<AiMemberLogListDTO>> aiRes = aiMemberLogApiService.lastAiMemberMarketingLog(memberIdList, aiThirdStatus, DateUtil.formatDate(startTime), DateUtil.formatDate(date), new HashMap<>());
        if (aiRes != null && aiRes.getResult() != null) {
            convertAiFollow(enterpriseId, aiRes.getResult(), followDTOList);
        }

        List<MemberSmsLogDTO> smsList = smsService.lastMemberSmsLog(enterpriseId, memberIdList, null, DateUtil.beginOfDay(startTime).toJdkDate(), DateUtil.endOfDay(date).toJdkDate(), new HashMap<>());
        convertSmsFollow(enterpriseId, smsList, followDTOList);

        Map<String, ContactFollowDTO> map = followDTOList.stream()
                .sorted(Comparator
                        .comparing(ContactFollowDTO::getFollowTime, Comparator.nullsLast(Comparator.reverseOrder()))
                        .thenComparing(ContactFollowDTO::getFollowType, Comparator.nullsLast(Comparator.naturalOrder()))
                        .thenComparing(ContactFollowDTO::getClerkId, Comparator.nullsLast(Comparator.naturalOrder()))
                ).collect(Collectors.toMap(
                        ContactFollowDTO::getMemberId,
                        v -> v,
                        (v1, v2) -> v1,
                        LinkedHashMap::new
                ));
        return map;
    }

    private List<ContactFollowDTO> convertExtInfo(List<TabContactFollow> list) {
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        Map<String, StoreGoodsVO> goodsMap = new HashMap<>();
        Set<String> goodsIdSet = list.stream().map(TabContactFollow::getGoodsInfo).filter(StringUtils::isNotBlank)
                .flatMap(x -> JSONArray.parseArray(x,String.class).stream()).collect(Collectors.toSet());
        // 组装商品信息
        if (CollectionUtils.isNotEmpty(goodsIdSet)) {
            ServiceResponse<List<StoreGoodsVO>> response = storeGoodsService.listByGoodsIds(Lists.newArrayList(goodsIdSet));
            if (response.isSuccess() && CollectionUtils.isNotEmpty(response.getResult())) {
                goodsMap = response.getResult().stream().collect(Collectors.toMap(StoreGoodsVO::getGoodsId, Function.identity(), (v1, v2) -> v1));
            }
        }
        Map<String, StoreGoodsVO> finalGoodsMap = goodsMap;
        List<ContactFollowDTO> pageList = list.stream().map(follow -> {
            ContactFollowDTO contactFollowDTO = EntityUtil.changeEntityNew(ContactFollowDTO.class, follow);
            String followMaterial = follow.getFollowMaterial();
            if (StringUtils.isNotBlank(followMaterial)) {
                contactFollowDTO.setFollowMaterialList(JSONArray.parseArray(followMaterial, String.class));
            }
            String goodsInfo = follow.getGoodsInfo();
            if (StringUtils.isNotBlank(goodsInfo)) {
                List<String> goodsIdList = JSONArray.parseArray(goodsInfo, String.class);
                List<ContactFollowGoodsDTO> goodsInfoList = goodsIdList.stream().map(goodsId -> {
                    StoreGoodsVO storeGoodsVO = finalGoodsMap.get(goodsId);
                    if (storeGoodsVO == null) {
                        return null;
                    }
                    return EntityUtil.changeEntityNew(ContactFollowGoodsDTO.class, storeGoodsVO);
                }).filter(Objects::nonNull).collect(Collectors.toList());
                contactFollowDTO.setGoodsInfoList(goodsInfoList);
            }
            return contactFollowDTO;
        }).collect(Collectors.toList());
        return pageList;
    }

}
