package com.slodon.b2b2c.util;

import cn.hutool.core.date.DateUtil;
import com.slodon.b2b2c.bo.StoreStatsBO;
import com.slodon.b2b2c.business.example.OrderExample;
import com.slodon.b2b2c.business.example.OrderProductExample;
import com.slodon.b2b2c.business.pojo.Order;
import com.slodon.b2b2c.business.pojo.OrderProduct;
import com.slodon.b2b2c.core.constant.GoodsConst;
import com.slodon.b2b2c.core.constant.OrderConst;
import com.slodon.b2b2c.core.util.FileUrlUtil;
import com.slodon.b2b2c.enums.StatsConstant;
import com.slodon.b2b2c.goods.example.GoodsBrandExample;
import com.slodon.b2b2c.goods.example.GoodsExample;
import com.slodon.b2b2c.goods.pojo.Goods;
import com.slodon.b2b2c.goods.pojo.GoodsBrand;
import com.slodon.b2b2c.member.example.MemberExample;
import com.slodon.b2b2c.member.example.MemberFollowStoreExample;
import com.slodon.b2b2c.member.pojo.Member;
import com.slodon.b2b2c.model.business.OrderModel;
import com.slodon.b2b2c.model.business.OrderProductModel;
import com.slodon.b2b2c.model.goods.GoodsBrandModel;
import com.slodon.b2b2c.model.goods.GoodsModel;
import com.slodon.b2b2c.model.member.MemberFollowStoreModel;
import com.slodon.b2b2c.model.member.MemberModel;
import com.slodon.b2b2c.statistics.pojo.MemberBehavior;
import com.slodon.b2b2c.statistics.pojo.base.StoreBase;
import com.slodon.b2b2c.vo.statistics.SellerPresentDataVO;
import org.springframework.beans.BeanUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

import static com.slodon.b2b2c.bo.BrandOrderBO.isOrderPay;

/**
 * 商户实时统计数据获取工具类
 */
@Component
public class SellerPresentDataUtil {

    @Resource
    private OrderModel orderModel;
    @Resource
    private OrderProductModel orderProductModel;
    @Resource
    private MemberModel memberModel;
    @Resource
    private GoodsModel goodsModel;
    @Resource
    private GoodsBrandModel goodsBrandModel;
    @Resource
    private MemberFollowStoreModel memberFollowStoreModel;
    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 计算实时统计数据
     *
     * @param startTime
     * @param endTime
     * @param storeId
     * @return
     */
    public SellerPresentDataVO calculatePresentData(Date startTime, Date endTime,String webSite, Long storeId) {
        SellerPresentDataVO vo = new SellerPresentDataVO();
        vo.setStatsTime(endTime);
        //店铺汇总
        vo.setSellerSummary(this.getSellerSummary(storeId,webSite));

        //查询今日统计基础数据
        //订单列表
        OrderExample orderExample = new OrderExample();
        orderExample.setStoreId(storeId);
        orderExample.setCreateTimeBefore(endTime);
        orderExample.setCreateTimeAfter(startTime);
        List<Order> orderList = orderModel.getOrderList(orderExample, null);
        Map<String/*orderSn*/, Order> orderMap = new HashMap<>();//订单map，便于查找订单
        //订单货品列表
        List<OrderProduct> orderProductList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(orderList)) {
            OrderProductExample orderProductExample = new OrderProductExample();
            StringBuilder orderSns = new StringBuilder();//构造orderSnIn
            orderList.forEach(order -> {
                orderSns.append(",'").append(order.getOrderSn()).append("'");
                orderMap.put(order.getOrderSn(), order);
            });

            orderProductExample.setOrderSnIn(orderSns.toString().substring(1));
            orderProductList = orderProductModel.getOrderProductList(orderProductExample, null);
        }
        //用户行为列表
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("behaviorTime").gte(startTime).lte(endTime).and("storeId").is(storeId).and("webSite").is(webSite);
        query.addCriteria(criteria);
        List<MemberBehavior> memberBehaviorList = mongoTemplate.find(query, MemberBehavior.class, "stats_member_behavior");
        //新增商品列表
        GoodsExample goodsExample = new GoodsExample();
        goodsExample.setStoreId(storeId);
        goodsExample.setWebSite(webSite);
        goodsExample.setCreateTimeBefore(endTime);
        goodsExample.setCreateTimeAfter(startTime);
        List<Goods> newGoodsList = goodsModel.getGoodsList(goodsExample, null);

        //新增品牌数
        GoodsBrandExample goodsBrandExample = new GoodsBrandExample();
        goodsBrandExample.setApplyStoreId(storeId);
        goodsBrandExample.setWebSite(webSite);
        goodsBrandExample.setState(GoodsConst.BRAND_STATE_1);
        goodsBrandExample.setCreateTimeBefore(endTime);
        goodsBrandExample.setCreateTimeAfter(startTime);
        List<GoodsBrand> newGoodsBrandList = goodsBrandModel.getGoodsBrandList(goodsBrandExample, null);

        //新增会员列表
        MemberExample memberExample = new MemberExample();
        memberExample.setRegisterTimeBefore(endTime);
        memberExample.setRegisterTimeAfter(startTime);
        memberExample.setWebSite(webSite);
        List<Member> newMemberList = memberModel.getMemberList(memberExample, null);

        StoreStatsBO storeStatsBO = new StoreStatsBO();
        storeStatsBO.setOrderList(orderList);
        storeStatsBO.setOrderProductList(orderProductList);
        storeStatsBO.setMemberBehaviorList(memberBehaviorList);
        storeStatsBO.setStoreNewGoodsList(newGoodsList);
        storeStatsBO.setStoreNewBrandList(newGoodsBrandList);
        storeStatsBO.setNewMemberList(newMemberList);

        //今日实时
        vo.setSellerTodaySummary(this.getSellerTodaySummary(storeStatsBO));

        //实时商品销售排行
        this.goodsSaleTop(orderProductList, orderMap, vo);

        //分时支付/下单金额
        this.timeOrderAmount(orderList, endTime, vo);

        //分时流量
        this.timePV(memberBehaviorList, endTime, vo);

        //分时新增用户数量
        this.timeNewMemberNum(memberBehaviorList, newMemberList, endTime, vo);

        return vo;
    }

    /**
     * 获取店铺汇总数据
     *
     * @return
     */
    private SellerPresentDataVO.SellerSummary getSellerSummary(Long storeId,String webSite) {
        //订单总额
        OrderExample orderExample = new OrderExample();
        orderExample.setOrderStateIn(OrderConst.ORDER_STATE_20 + "," + OrderConst.ORDER_STATE_30 + "," + OrderConst.ORDER_STATE_40);
        orderExample.setStoreId(storeId);
        BigDecimal totalSaleAmount = orderModel.getTotalSaleAmount(orderExample);

        //用户总数，在本店铺有过浏览行为的历史去重人数总和
        Criteria condition = Criteria.where("behaviorType").is(StatsConstant.STORE_PAGE_VIEW);
        Criteria condition1 = Criteria.where("behaviorType").is(StatsConstant.GOODS_PAGE_VIEW);
        Criteria condition2 = new Criteria().orOperator(condition, condition1);
        Criteria criteria = Criteria.where("storeId").is(storeId).and("memberId").ne(0).andOperator(condition2);
        Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(criteria), Aggregation.group("memberId").count().as("memberNum"));
        AggregationResults<ModelMap> results = mongoTemplate.aggregate(aggregation, "stats_member_behavior", ModelMap.class);
        int memberNum = results.getMappedResults().size();

        //在售商品总数
        GoodsExample goodsExample = new GoodsExample();
        goodsExample.setStoreId(storeId);
        goodsExample.setStateNotEquals(GoodsConst.GOODS_STATE_DELETE);
        goodsExample.setWebSite(webSite);
        Integer goodsNum = goodsModel.getGoodsCount(goodsExample);
        goodsExample.setState(GoodsConst.GOODS_STATE_UPPER);
        Integer goodsCount = goodsModel.getGoodsCount(goodsExample);

        //关注店铺人数
        MemberFollowStoreExample memberFollowStoreExample = new MemberFollowStoreExample();
        memberFollowStoreExample.setStoreId(storeId);
        Integer memberFollowStoreCount = memberFollowStoreModel.getMemberFollowStoreCount(memberFollowStoreExample);

        SellerPresentDataVO.SellerSummary sellerSummary = new SellerPresentDataVO.SellerSummary();
        sellerSummary.setOrderPayAmount(totalSaleAmount);
        sellerSummary.setMemberNum(memberNum);
        sellerSummary.setGoodsNum(goodsNum);
        sellerSummary.setSaleGoodsNum(goodsCount);
        sellerSummary.setFollowMemberNum(memberFollowStoreCount);

        return sellerSummary;
    }

    /**
     * 获取今日实时数据
     *
     * @param storeStatsBO
     * @return
     */
    private SellerPresentDataVO.SellerTodaySummary getSellerTodaySummary(StoreStatsBO storeStatsBO) {
        SellerPresentDataVO.SellerTodaySummary todaySummary = new SellerPresentDataVO.SellerTodaySummary();

        //构造店铺统计数据
        StoreBase storeBase = storeStatsBO.initStats(null);

        //复制数据
        BeanUtils.copyProperties(storeBase, todaySummary);
        return todaySummary;
    }

    /**
     * 构造商品销售top10
     *
     * @param orderProductList
     * @return
     */
    private void goodsSaleTop(List<OrderProduct> orderProductList, Map<String/*orderSn*/, Order> orderMap, SellerPresentDataVO vo) {
        Map<Long/*goodsId*/, SellerPresentDataVO.SellerGoodsSale> goodsSaleMap = new HashMap<>();
        orderProductList.forEach(orderProduct -> {
            int saleNum = orderProduct.getProductNum();//销量
            BigDecimal saleAmount = isOrderPay(orderMap.get(orderProduct.getOrderSn())) ? orderProduct.getMoneyAmount() : new BigDecimal("0.00");
            //按照商品分组
            if (goodsSaleMap.containsKey(orderProduct.getGoodsId())) {
                SellerPresentDataVO.SellerGoodsSale sellerGoodsSale = goodsSaleMap.get(orderProduct.getGoodsId());
                //增加销量
                sellerGoodsSale.setSaleNum(sellerGoodsSale.getSaleNum() + saleNum);
                //增加销售额
                sellerGoodsSale.setSaleAmount(sellerGoodsSale.getSaleAmount().add(saleAmount));
            } else {
                SellerPresentDataVO.SellerGoodsSale sellerGoodsSale = new SellerPresentDataVO.SellerGoodsSale();
                sellerGoodsSale.setGoodsId(orderProduct.getGoodsId());
                sellerGoodsSale.setGoodsName(orderProduct.getGoodsName());
                sellerGoodsSale.setGoodsImage(FileUrlUtil.getFileUrl(orderProduct.getProductImage(), null));
                sellerGoodsSale.setSaleAmount(saleAmount);
                sellerGoodsSale.setSaleNum(saleNum);
                goodsSaleMap.put(orderProduct.getGoodsId(), sellerGoodsSale);
            }
        });

        List<SellerPresentDataVO.SellerGoodsSale> goodsSaleList = new ArrayList<>(goodsSaleMap.values());
        //排行数量，最大10个
        int topNum = Integer.min(10, goodsSaleList.size());
        //按销量倒序排
        goodsSaleList.sort((o1, o2) -> o2.getSaleNum().compareTo(o1.getSaleNum()));
        vo.getGoodsSaleNumList().addAll(goodsSaleList.subList(0, topNum));

        //按销售额倒序排
        goodsSaleList.sort((o1, o2) -> o2.getSaleAmount().compareTo(o1.getSaleAmount()));
        vo.getGoodsSaleAmountList().addAll(goodsSaleList.subList(0, topNum));
    }

    private void orderPayAmountDistribute(List<Order> orderList, Date endTime, SellerPresentDataVO vo) {
        List<BigDecimal/*orderPayAmount*/> orderPayAmountList = new ArrayList<>();
        orderList.forEach(order -> {
            if (isOrderPay(order)) {
                orderPayAmountList.add(order.getOrderAmount());
            }
        });
        if (CollectionUtils.isEmpty(orderPayAmountList)) {
            return;
        }

        //获取最大订单金额
        orderPayAmountList.sort(Comparator.reverseOrder());
        BigDecimal maxAmount = orderPayAmountList.get(0);

        //展示4个分布区间
    }

    /**
     * 分时支付/下单金额
     *
     * @param orderList 时段订单列表
     * @param endTime   截止时间
     * @param vo
     */
    private void timeOrderAmount(List<Order> orderList, Date endTime, SellerPresentDataVO vo) {
        Map<String/*hour*/, SellerPresentDataVO.SellerTimeAmount> hourSubmitAmountMap = new HashMap<>();
        Map<String/*hour*/, SellerPresentDataVO.SellerTimeAmount> hourPayAmountMap = new HashMap<>();

        orderList.forEach(order -> {
            //按小时增加下单金额
            int hour = DateUtil.hour(order.getCreateTime(), true);
            String hourStr = hour > 9 ? hour + ":00" : "0" + hour + ":00";
            if (hourSubmitAmountMap.containsKey(hourStr)) {
                hourSubmitAmountMap.get(hourStr).addAmount(order.getOrderAmount());
            } else {
                hourSubmitAmountMap.put(hourStr, new SellerPresentDataVO.SellerTimeAmount(hourStr, order.getOrderAmount()));
            }

            if (isOrderPay(order)) {
                //订单已支付，按小时增加支付金额
                if (hourPayAmountMap.containsKey(hourStr)) {
                    hourPayAmountMap.get(hourStr).addAmount(order.getOrderAmount());
                } else {
                    hourPayAmountMap.put(hourStr, new SellerPresentDataVO.SellerTimeAmount(hourStr, order.getOrderAmount()));
                }
            }
        });

        //按小时循环构造列表，从0开始
        for (int i = 0; i <= DateUtil.hour(endTime, true); i++) {
            String hourStr = i > 9 ? i + ":00" : "0" + i + ":00";
            vo.getOrderSubmitAmountList().add(hourSubmitAmountMap.getOrDefault(hourStr, new SellerPresentDataVO.SellerTimeAmount(hourStr, new BigDecimal("0.00"))));
            vo.getOrderPayAmountList().add(hourPayAmountMap.getOrDefault(hourStr, new SellerPresentDataVO.SellerTimeAmount(hourStr, new BigDecimal("0.00"))));
        }
    }

    /**
     * 分时流量
     *
     * @param memberBehaviorList 时段会员行为
     * @param endTime            截止时间
     * @param vo
     */
    private void timePV(List<MemberBehavior> memberBehaviorList, Date endTime, SellerPresentDataVO vo) {
        Map<String/*hour*/, SellerPresentDataVO.SellerTimeNum> hourViewNumMap = new HashMap<>();//浏览量
        Map<String/*hour*/, Set<Integer/*memberId*/>> hourVisitorNumMap = new HashMap<>();//访客数

        memberBehaviorList.forEach(memberBehavior -> {
            if (StatsConstant.STORE_PAGE_VIEW.equals(memberBehavior.getBehaviorType())) {
                //浏览类型
                //按小时增加浏览量
                int hour = DateUtil.hour(memberBehavior.getBehaviorTime(), true);
                String hourStr = hour > 9 ? hour + ":00" : "0" + hour + ":00";
                if (hourViewNumMap.containsKey(hourStr)) {
                    hourViewNumMap.get(hourStr).addNum(1);
                } else {
                    hourViewNumMap.put(hourStr, new SellerPresentDataVO.SellerTimeNum(hourStr, 1));
                }

                //按小时统计访客数
                if (hourVisitorNumMap.containsKey(hourStr)) {
                    hourVisitorNumMap.get(hourStr).add(memberBehavior.getMemberId());
                } else {
                    Set<Integer> set = new HashSet<>();
                    set.add(memberBehavior.getMemberId());
                    hourVisitorNumMap.put(hourStr, set);
                }
            }
        });

        //按小时循环构造列表，从0开始
        for (int i = 0; i <= DateUtil.hour(endTime, true); i++) {
            String hourStr = i > 9 ? i + ":00" : "0" + i + ":00";
            vo.getViewNumList().add(hourViewNumMap.getOrDefault(hourStr, new SellerPresentDataVO.SellerTimeNum(hourStr, 0)));
            vo.getVisitorNumList().add(new SellerPresentDataVO.SellerTimeNum(hourStr, hourVisitorNumMap.getOrDefault(hourStr, new HashSet<>()).size()));
        }
    }


    /**
     * 分时新增会员数
     *
     * @param memberBehaviorList
     * @param newMemberList
     * @param endTime
     * @param vo
     */
    private void timeNewMemberNum(List<MemberBehavior> memberBehaviorList, List<Member> newMemberList, Date endTime, SellerPresentDataVO vo) {
        Map<String/*hour*/, Set<Integer/*memberId*/>> newMemberNumMap = new HashMap<>();//每个小时的新会员数
        Map<String/*hour*/, Set<Integer/*memberId*/>> hourNewMemberMap = new HashMap<>();//每个小时注册的新会员id集合
        newMemberList.forEach(member -> {
            int hour = DateUtil.hour(member.getRegisterTime(), true);
            String hourStr = hour > 9 ? hour + ":00" : "0" + hour + ":00";
            if (hourNewMemberMap.containsKey(hourStr)) {
                hourNewMemberMap.get(hourStr).add(member.getMemberId());
            } else {
                Set<Integer> set = new HashSet<>();
                set.add(member.getMemberId());
                hourNewMemberMap.put(hourStr, set);
            }
        });

        memberBehaviorList.forEach(memberBehavior -> {
            if (StatsConstant.STORE_PAGE_VIEW.equals(memberBehavior.getBehaviorType())) {
                //浏览类型
                int hour = DateUtil.hour(memberBehavior.getBehaviorTime(), true);
                String hourStr = hour > 9 ? hour + ":00" : "0" + hour + ":00";
                Set<Integer> memberIdSet = hourNewMemberMap.getOrDefault(hourStr, new HashSet<>());//获取该小时的注册会员
                if (memberIdSet.contains(memberBehavior.getMemberId())) {
                    //这条浏览记录是新注册会员浏览的
                    if (newMemberNumMap.containsKey(hourStr)) {
                        newMemberNumMap.get(hourStr).add(memberBehavior.getMemberId());
                    } else {
                        Set<Integer> set = new HashSet<>();
                        set.add(memberBehavior.getMemberId());
                        newMemberNumMap.put(hourStr, set);
                    }
                }
            }
        });

        //按小时循环构造列表，从0开始
        for (int i = 0; i <= DateUtil.hour(endTime, true); i++) {
            String hourStr = i > 9 ? i + ":00" : "0" + i + ":00";
            vo.getNewMemberNumList().add(new SellerPresentDataVO.SellerTimeNum(hourStr, newMemberNumMap.getOrDefault(hourStr, new HashSet<>()).size()));
        }
    }
}
