package com.kiisoo.ic.store.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.kiisoo.aegis.common.faces.util.HttpUtil;
import com.kiisoo.ic.common.utils.MD5FileUtil;
import com.kiisoo.ic.config.WxCpConfiguration;
import com.kiisoo.ic.domain.service.PrivilageDomainService;
import com.kiisoo.ic.store.constant.Constants;
import com.kiisoo.ic.store.entity.StaffDO;
import com.kiisoo.ic.store.entity.StorePromotionDataDO;
import com.kiisoo.ic.store.entity.WxCusInfoReqDO;
import com.kiisoo.ic.store.entity.WxCusInfoRespDO;
import com.kiisoo.ic.store.mapper.StorePromotionDataDOMapper;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: JYJ
 * @Date: 2020/4/10 10:50
 * @Version: v1.0
 */
@Service
@Slf4j
public class StorePromotionDataService {

    private WxCpService mainService = WxCpConfiguration.getCpService(1000037);

    /**
     * 门店数据mapper
     */
    @Autowired
    private StorePromotionDataDOMapper storePromotionDataDOMapper;

    /**
     * 权限业务
     */
    @Autowired
    private PrivilageDomainService privilageDomainService;

    /**
     * 查询门店推广数据列表
     * @param storeId
     * @param regionId
     * @param sellerId
     * @param startDate
     * @param endDate
     * @param pageNum
     * @param pageSize
     * @return
     */
    public PageInfo<StorePromotionDataDO> listStorePromotionData(Long userId, Long storeId, Long regionId, Long sellerId,
                                                                 Date startDate, Date endDate, String type, int pageNum, int pageSize) {
        //用户权限下的店铺
        List<Long> storeIds = privilageDomainService.listUserDatePermission(userId);
        // 查询三种类型的新增客户数
        List<StorePromotionDataDO> promotionDataDOS;
        // 查询三种类型的新增客户数 (去重完) 转map
        List<StorePromotionDataDO> newCusNumDOSExclude;
        Map<Long, Integer> newCusNumMapExclude;

        // 查询三种类型的总客户数 日期区间 转map
        List<StorePromotionDataDO> cusNumDataDOS;
        Map<Long, StorePromotionDataDO> cusNumMap;
        // 查询三种类型的总客户数 日期区间 (去重完) 转map
        List<StorePromotionDataDO> cusNumDataDOSExclude;
        Map<Long, StorePromotionDataDO> cusNumMapExclude;

        // 查询拉黑数量 转map
        List<StorePromotionDataDO> wxCusInfoDO;
        Map<Long, Integer> delCusNumMap = null;
        if (Constants.STORE_DATA_TYPE_REGION.equals(type)) {
            PageHelper.startPage(pageNum, pageSize);
            promotionDataDOS = storePromotionDataDOMapper.selectPromotionDataGroupByRegion(storeIds, regionId, startDate, endDate, null);

            newCusNumDOSExclude = storePromotionDataDOMapper.selectPromotionDataGroupByRegion(storeIds, regionId, startDate, endDate, Constants.STORE_SELLER_CUS_RELATION_TYPE_VALID);
            newCusNumMapExclude = newCusNumDOSExclude.stream().collect(Collectors.toMap(StorePromotionDataDO::getRegionId, StorePromotionDataDO::getNewCusNum, (k1, k2) -> k1));

            cusNumDataDOS = storePromotionDataDOMapper.selectSumCusNumGroupByRegion(storeIds,regionId, null);
            cusNumMap = cusNumDataDOS.stream().collect(Collectors.toMap(StorePromotionDataDO::getRegionId, s -> s, (k1, k2) -> k1));

            cusNumDataDOSExclude = storePromotionDataDOMapper.selectSumCusNumGroupByRegion(storeIds,regionId, Constants.STORE_SELLER_CUS_RELATION_TYPE_VALID);
            cusNumMapExclude = cusNumDataDOSExclude.stream().collect(Collectors.toMap(StorePromotionDataDO::getRegionId, s -> s, (k1, k2) -> k1));

            wxCusInfoDO = storePromotionDataDOMapper.selectWxCusInfoByRegionId(startDate, endDate);
            delCusNumMap = wxCusInfoDO.stream().collect(Collectors.toMap(StorePromotionDataDO::getRegionId, StorePromotionDataDO::getDelCusNum, (k1, k2) -> k1));
        } else if (Constants.STORE_DATA_TYPE_STORE.equals(type)){
            PageHelper.startPage(pageNum, pageSize);
            promotionDataDOS = storePromotionDataDOMapper.selectPromotionDataGroupByStore(storeIds, storeId, regionId, startDate, endDate, null);

            newCusNumDOSExclude = storePromotionDataDOMapper.selectPromotionDataGroupByStore(storeIds, storeId, regionId, startDate, endDate, Constants.STORE_SELLER_CUS_RELATION_TYPE_VALID);
            newCusNumMapExclude = newCusNumDOSExclude.stream().collect(Collectors.toMap(StorePromotionDataDO::getStoreId, StorePromotionDataDO::getNewCusNum, (k1, k2) -> k1));

            cusNumDataDOS = storePromotionDataDOMapper.selectSumCusNumGroupByStore(storeIds, storeId, regionId, null);
            cusNumMap = cusNumDataDOS.stream().collect(Collectors.toMap(StorePromotionDataDO::getStoreId, s -> s, (k1, k2) -> k1));

            cusNumDataDOSExclude = storePromotionDataDOMapper.selectSumCusNumGroupByStore(storeIds, storeId, regionId, Constants.STORE_SELLER_CUS_RELATION_TYPE_VALID);
            cusNumMapExclude = cusNumDataDOSExclude.stream().collect(Collectors.toMap(StorePromotionDataDO::getStoreId, s -> s, (k1, k2) -> k1));

            wxCusInfoDO = storePromotionDataDOMapper.selectWxCusInfoByStoreId(startDate, endDate);
            delCusNumMap = wxCusInfoDO.stream().collect(Collectors.toMap(StorePromotionDataDO::getStoreId, StorePromotionDataDO::getDelCusNum, (k1, k2) -> k1));
        } else {
            PageHelper.startPage(pageNum, pageSize);
            promotionDataDOS = storePromotionDataDOMapper.selectPromotionDataGroupBySeller(storeIds, storeId, regionId, sellerId, startDate, endDate, null);

            newCusNumDOSExclude = storePromotionDataDOMapper.selectPromotionDataGroupBySeller(storeIds, storeId, regionId, sellerId, startDate, endDate, Constants.STORE_SELLER_CUS_RELATION_TYPE_VALID );
            newCusNumMapExclude = newCusNumDOSExclude.stream().collect(Collectors.toMap(StorePromotionDataDO::getStoreId, StorePromotionDataDO::getNewCusNum, (k1, k2) -> k1));

            cusNumDataDOS = storePromotionDataDOMapper.selectSumCusNumGroupBySeller(storeIds, storeId, regionId, sellerId, null);
            cusNumMap = cusNumDataDOS.stream().collect(Collectors.toMap(StorePromotionDataDO::getSellerId, s -> s, (k1, k2) -> k1));

            cusNumDataDOSExclude = storePromotionDataDOMapper.selectSumCusNumGroupBySeller(storeIds, storeId, regionId, sellerId, Constants.STORE_SELLER_CUS_RELATION_TYPE_VALID);
            cusNumMapExclude = cusNumDataDOSExclude.stream().collect(Collectors.toMap(StorePromotionDataDO::getStoreId, s -> s, (k1, k2) -> k1));
        }


        Map<Long, StorePromotionDataDO> finalCusNumMap = cusNumMap;
        Map<Long, Integer> finalDelCusNumMap = delCusNumMap;
        promotionDataDOS.forEach(promotionDataDO -> {
            Long storeIdKey = promotionDataDO.getStoreId();
            Long regionIdKey = promotionDataDO.getRegionId();
            Long sellerIdKey = promotionDataDO.getSellerId();
            //填充门店数据
            if (Constants.STORE_DATA_TYPE_REGION.equals(type)) {
                addPromotionData(promotionDataDO, regionIdKey, newCusNumMapExclude, finalCusNumMap,
                        cusNumMapExclude, finalDelCusNumMap, type);
            } else if (Constants.STORE_DATA_TYPE_STORE.equals(type)) {
                addPromotionData(promotionDataDO, storeIdKey, newCusNumMapExclude, finalCusNumMap,
                        cusNumMapExclude, finalDelCusNumMap, type);
            } else {
                addPromotionData(promotionDataDO, sellerIdKey, newCusNumMapExclude, finalCusNumMap,
                        cusNumMapExclude, finalDelCusNumMap, type);
            }
        });
        return new PageInfo<>(promotionDataDOS);
    }

    /**
     * 填充门店数据
     * @param promotionDataDO 数据对象
     * @param keyId 数据keyId regionId/storeId/sellerId
     * @param newCusNumMapExclude 新增客户Map
     * @param finalCusNumMap 总客户Map
     * @param finalCusNumMapExclude 总客户剔除完Map
     * @param finalDelCusNumMap 拉黑客户数Map
     * @param type 数据查询类型
     */
    private void addPromotionData(StorePromotionDataDO promotionDataDO,
                                  Long keyId, Map<Long, Integer> newCusNumMapExclude,
                                  Map<Long, StorePromotionDataDO> finalCusNumMap,
                                  Map<Long, StorePromotionDataDO> finalCusNumMapExclude,
                                  Map<Long, Integer> finalDelCusNumMap, String type) {
        // 新增客户数量 (去重完)
        Integer newCusNumExclude = newCusNumMapExclude == null || newCusNumMapExclude.get(keyId) == null ? null : newCusNumMapExclude.get(keyId);
        // 客户总数
        Integer cusNum = finalCusNumMap == null || finalCusNumMap.get(keyId) == null ? null : finalCusNumMap.get(keyId).getCusNum();
        // 客户总数 (去重完)
        Integer cusNumExclude = finalCusNumMapExclude == null || finalCusNumMapExclude.get(keyId) == null ? null : finalCusNumMapExclude.get(keyId).getCusNum();
        // 最小日期
        Date minDate = finalCusNumMap == null || finalCusNumMap.get(keyId) == null ? null : finalCusNumMap.get(keyId).getMinDate();
        // 最大日期
        Date maxDate = finalCusNumMap == null || finalCusNumMap.get(keyId) == null ? null : finalCusNumMap.get(keyId).getMaxDate();
        // 最小日期 (去重完)
        Date minDateExclude = finalCusNumMapExclude == null || finalCusNumMapExclude.get(keyId) == null ? null : finalCusNumMapExclude.get(keyId).getMinDate();
        // 最大日期 (去重完)
        Date maxDateExclude = finalCusNumMapExclude == null || finalCusNumMapExclude.get(keyId) == null ? null : finalCusNumMapExclude.get(keyId).getMaxDate();
        // 被拉黑客户数
        Integer delCusNum = finalDelCusNumMap == null || finalDelCusNumMap.get(keyId) == null  ? null : finalDelCusNumMap.get(keyId);
        // 新增客户数 (去重完)
        if (newCusNumExclude != null) {
            promotionDataDO.setNewCusNumExclude(newCusNumExclude);
        }
        // 客户总数 (去重完)
        if (cusNumExclude != null) {
            promotionDataDO.setCusNumExclude(cusNumExclude);
        }
        // 拉黑数 拉黑率 拉黑/总客户
        if (!Constants.STORE_DATA_TYPE_SELLER.equals(type)) {
            if (null != delCusNum) {
                promotionDataDO.setDelCusNum(delCusNum);
                promotionDataDO.setDelCusRate(cusNum == null || cusNum == Constants.CONTACT_COUNT_ZERO ?
                        0 : delCusNum * 1f / promotionDataDO.getCusNum());
            }
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            // 日增好友平均 总客户/天
            if (minDate != null && maxDate != null) {
                Date minDateF = sdf.parse(sdf.format(minDate));
                Date maxDateF = sdf.parse(sdf.format(minDate));
                int nDay = maxDateF.getTime() - minDateF.getTime() == 0 ? 1 : (int) ((maxDateF.getTime() - minDateF.getTime()) / (24 * 60 * 60 * 1000));
                if (cusNum != null) {
                    promotionDataDO.setAvgNewCusNum(cusNum / nDay);
                }
            }
            // 日增好友平均 (去重完)
            if (minDateExclude != null && maxDateExclude != null) {
                Date minDateFExclude = sdf.parse(sdf.format(minDateExclude));
                Date maxDateFExclude = sdf.parse(sdf.format(maxDateExclude));
                int nDay = maxDateFExclude.getTime() - minDateFExclude.getTime() == 0 ? 1 : (int) ((maxDateFExclude.getTime() - minDateFExclude.getTime()) / (24 * 60 * 60 * 1000));
                if (cusNumExclude != null) {
                    promotionDataDO.setAvgNewCusNumExclude(cusNumExclude / nDay);
                }
            }
        } catch (ParseException e) {
            log.error("查询门店推广数据列表日期转换出错！", e);
        }
    }

    /**
     * 同步企业微信的拉黑和新增客户信息
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public void syncCustomerBlackList() throws Exception{
        //获取token
        String token = mainService.getAccessToken();
        List<StorePromotionDataDO> cusList = storePromotionDataDOMapper.selectCustomer();
        cusList.forEach(customer -> {
            // 返回
            try {
                String userId = customer.getUserId();
                WxCusInfoReqDO wxCusInfoReqDO = new WxCusInfoReqDO();
                wxCusInfoReqDO.setAccess_token(token);
                wxCusInfoReqDO.setUserid(userId);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                //todo 分开写便于同步历史数据 最大跨度30天 最久当天往前180天 上线时改为System.currentTimeMillis()
                Date startDate = sdf.parse("2020-04-12");
                Date endDate = sdf.parse("2020-04-12");
                wxCusInfoReqDO.setStart_time(startDate.getTime()/1000);
                wxCusInfoReqDO.setEnd_time(endDate.getTime()/1000);
                WxCusInfoRespDO wxCusInfoRespDO = getWxCusInfoBSD(wxCusInfoReqDO);
                if (wxCusInfoRespDO.getNegative_feedback_cnt() == Constants.CONTACT_COUNT_ZERO &&
                        wxCusInfoRespDO.getNew_contact_cnt() == Constants.CONTACT_COUNT_ZERO) {
                    return;
                }
                wxCusInfoRespDO.setStoreId(customer.getStoreId());
                wxCusInfoRespDO.setRegionId(customer.getRegionId());
                wxCusInfoRespDO.setStatTime(startDate);
                int syncRes = storePromotionDataDOMapper.insertStorePromotionData(wxCusInfoRespDO);
                if (syncRes == Constants.INSERT_FAIL) {
                    throw new RuntimeException("向数据库导入客户统计数据时出错");
                }
            } catch (WxErrorException | ParseException e) {
                log.error("请求企业微信api获取客户统计数据或日期转换出错！", e);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }


    /**
     * 获取联系客户统计数据
     *
     * @param wxCusInfoReqDO
     * @return
     * @throws WxErrorException
     */
    public WxCusInfoRespDO getWxCusInfo(WxCusInfoReqDO wxCusInfoReqDO) throws WxErrorException {
        String url = mainService.getWxCpConfigStorage().getApiUrl("/cgi-bin/externalcontact/get_user_behavior_data");
        String result = mainService.post(url, wxCusInfoReqDO.toJson());
        JSONObject parseObject = JSON.parseObject(result);
        System.out.println(parseObject);
        String[] behavior_data = JSONObject.parseObject(parseObject.getString("behavior_data"), String[].class);
        return JSONObject.parseObject(behavior_data[0], WxCusInfoRespDO.class);
    }

    /**
     * 获取联系客户统计数据
     *
     * @param wxCusInfoReqDO
     * @return
     * @throws WxErrorException
     */
    public WxCusInfoRespDO getWxCusInfoBSD(WxCusInfoReqDO wxCusInfoReqDO) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Map<String,Object> params = new HashMap<>();
        params.put("start_time",wxCusInfoReqDO.getStart_time());
        params.put("end_time",wxCusInfoReqDO.getEnd_time());
        params.put("userid",wxCusInfoReqDO.getUserid());
        String result = HttpUtil.get("http://vtest.bsd.cn/BSD_WXAPP/qyWechat/getUserBehaviorData?token==BOSIDENG" + MD5FileUtil.getMD5String(sdf.format(new Date())), params);
        JSONObject parseObject = JSON.parseObject(result);
        System.out.println(parseObject);
        String[] behavior_data = JSONObject.parseObject(parseObject.getString("behavior_data"), String[].class);
        return JSONObject.parseObject(behavior_data[0], WxCusInfoRespDO.class);
    }

    /**
     * 查询门店推广数据列表 手机端
     * @param userId
     * @param roleCode
     * @param startDate
     * @param endDate
     * @return
     */
    public StorePromotionDataDO listStorePromotionDataWx(Long userId, String roleCode,
                                                               Date startDate, Date endDate, Date lastStartDate, Date lastEndDate) {
        StorePromotionDataDO storePromotionDataDO = new StorePromotionDataDO();
        Integer cusNum = null;
        Integer newCusNum = null;
        Integer newCusNumLast = null;
        Integer rankNo = null;
        Integer differFromChampion = null;
        switch (roleCode) {
            // 店长
            case Constants.WX_USER_ROLE_SHOP_MANAGER:
                Long storeId = storePromotionDataDOMapper.selectStoreIdByUserId(userId);
                if (storeId == null) {
                    break;
                }
                cusNum = storePromotionDataDOMapper.selectWxSumCusNumByCondition(null, storeId, null, null, Constants.STORE_SELLER_CUS_RELATION_TYPE_VALID);
                newCusNum = storePromotionDataDOMapper.selectWxSumCusNumByCondition(null, storeId, startDate, endDate, Constants.STORE_SELLER_CUS_RELATION_TYPE_VALID);
                newCusNumLast = storePromotionDataDOMapper.selectWxSumCusNumByCondition(null, storeId, lastStartDate, lastEndDate, Constants.STORE_SELLER_CUS_RELATION_TYPE_VALID);
                // 店铺排名
                List<StorePromotionDataDO> storeRankNoList = storePromotionDataDOMapper.selectStoreRankNo(startDate, endDate);
                if (CollectionUtils.isNotEmpty(storeRankNoList)) {
                    for (int i = 0; i < storeRankNoList.size(); i++) {
                        if (storeRankNoList.get(i).getStoreId().equals(storeId)) {
                            rankNo = storeRankNoList.get(i).getRankNo();
                            Integer curNewCusNum = storeRankNoList.get(i).getNewCusNum();
                            Integer championNewCusNum = storeRankNoList.get(0).getNewCusNum();
                            differFromChampion = championNewCusNum - curNewCusNum;
                            break;
                        }
                    }
                }
                // 导购列表
                List<StaffDO> staffDOList = storePromotionDataDOMapper.selectWxValidStaffNameList(storeId);
                // 导购新增客户数列表
                List<StaffDO> staffNewCusNumList = storePromotionDataDOMapper.selectWxStaffDOList(storeId, startDate, endDate);
                Map<Long, Integer> staffNewCusNumMap = staffNewCusNumList.stream().collect(Collectors.toMap(StaffDO::getId, StaffDO::getCusNum, (k1, k2) -> k1));
                // 导购总客户数
                List<StaffDO> staffCusNumList = storePromotionDataDOMapper.selectWxStaffDOList(storeId, null, null);
                Map<Long, Integer> staffCusNumMap = staffCusNumList.stream().collect(Collectors.toMap(StaffDO::getId, StaffDO::getCusNum, (k1, k2) -> k1));
                staffDOList.forEach(storeDO ->{
                    Long id = storeDO.getId();
                    if (null != staffCusNumMap && staffCusNumMap.get(id) != null) {
                        storeDO.setCusNum(staffCusNumMap.get(id));
                    }
                    if (null != staffNewCusNumMap && staffNewCusNumMap.get(id) != null) {
                        storeDO.setNewCusNum(staffNewCusNumMap.get(id));
                    }
                });
                if (CollectionUtils.isNotEmpty(staffDOList)) {
                    // 总客户数降序
                    List<StaffDO> staffFinalList = staffDOList.stream().sorted(Comparator.comparing(StaffDO::getCusNum, Comparator.nullsFirst(Integer::compareTo)).reversed()).collect(Collectors.toList());
                    storePromotionDataDO.setStaffDOList(staffFinalList);
                }
                break;
            // 导购
            case Constants.WX_USER_ROLE_STAFF:
                cusNum = storePromotionDataDOMapper.selectWxSumCusNumByCondition(userId, null, null, null, null);
                newCusNum = storePromotionDataDOMapper.selectWxSumCusNumByCondition(userId, null, startDate, endDate, null);
                newCusNumLast = storePromotionDataDOMapper.selectWxSumCusNumByCondition(userId, null, lastStartDate, lastEndDate, null);
                // 店铺排名
                List<StorePromotionDataDO> staffRankNoList = storePromotionDataDOMapper.selectStaffRankNo(startDate, endDate);
                if (CollectionUtils.isNotEmpty(staffRankNoList)) {
                    for (int i = 0; i < staffRankNoList.size(); i++) {
                        if (staffRankNoList.get(i).getUserId().equals(userId.toString())) {
                            rankNo = staffRankNoList.get(i).getRankNo();
                            Integer curNewCusNum = staffRankNoList.get(i).getNewCusNum();
                            Integer championNewCusNum = staffRankNoList.get(0).getNewCusNum();
                            differFromChampion = championNewCusNum - curNewCusNum;
                            break;
                        }
                    }
                }
                break;
            default:
                break;
        }
        if (null != cusNum) {
            storePromotionDataDO.setCusNum(cusNum);
        }
        if (null != newCusNum) {
            storePromotionDataDO.setNewCusNum(newCusNum);
        }
        if (null != newCusNumLast) {
            storePromotionDataDO.setNewCusNumLast(newCusNumLast);
        }
        if (null != rankNo) {
            storePromotionDataDO.setRankNo(rankNo);
        }
        if (null != differFromChampion) {
            storePromotionDataDO.setDifferFromChampion(differFromChampion);
        }
        return storePromotionDataDO;
    }
}
