package com.slodon.b2b2c.util;

import cn.hutool.core.date.DateUtil;
import com.slodon.b2b2c.bo.*;
import com.slodon.b2b2c.business.example.OrderExample;
import com.slodon.b2b2c.business.pojo.Order;
import com.slodon.b2b2c.core.constant.GoodsConst;
import com.slodon.b2b2c.core.constant.OrderConst;
import com.slodon.b2b2c.core.constant.StoreConst;
import com.slodon.b2b2c.enums.StatsConstant;
import com.slodon.b2b2c.goods.example.GoodsExample;
import com.slodon.b2b2c.member.example.MemberExample;
import com.slodon.b2b2c.member.pojo.Member;
import com.slodon.b2b2c.model.business.OrderModel;
import com.slodon.b2b2c.model.goods.GoodsModel;
import com.slodon.b2b2c.model.member.MemberModel;
import com.slodon.b2b2c.model.seller.StoreModel;
import com.slodon.b2b2c.seller.example.StoreExample;
import com.slodon.b2b2c.seller.pojo.Store;
import com.slodon.b2b2c.statistics.pojo.MemberBehavior;
import com.slodon.b2b2c.statistics.pojo.base.CategoryBase;
import com.slodon.b2b2c.statistics.pojo.base.GoodsBase;
import com.slodon.b2b2c.statistics.pojo.base.PlatformBase;
import com.slodon.b2b2c.statistics.pojo.base.StoreBase;
import com.slodon.b2b2c.vo.statistics.AdminPresentDataVO;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestParam;

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

/**
 * 平台实时统计数据获取工具类
 */
@Component
public class PlatformPresentDataUtil {

    @Resource
    private OrderModel orderModel;
    @Resource
    private MemberModel memberModel;
    @Resource
    private StoreModel storeModel;
    @Resource
    private GoodsModel goodsModel;
    @Resource
    private StatsDataUtil statsDataUtil;

    /**
     * 计算实时统计数据
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public AdminPresentDataVO calculatePresentData(Date startTime, Date endTime,String webSite) {
        AdminPresentDataVO vo = new AdminPresentDataVO();
        vo.setStatsTime(endTime);
        //平台汇总
        vo.setPlatformSummary(this.getPlatformSummary(webSite));

        //查询今日统计基础数据
        StatsBasicDataBO basicDataBO = statsDataUtil.searchStatsBasicData(startTime, endTime, webSite);

        //今日实时
        vo.setPlatformTodaySummary(this.getPlatformTodaySummary(basicDataBO));

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

        //实时店铺销售排行
        this.storeSaleTop(basicDataBO, vo);

        //实时商品分类销售排行
        this.categorySaleTop(basicDataBO, vo);

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

        //分时会员新增
        this.timeNewMemberNum(basicDataBO.getNewMemberList(), endTime, vo);

        //分时店铺新增
        this.timeNewStoreNum(basicDataBO.getNewStoreList(), endTime, vo);

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

        return vo;
    }

    /**
     * 获取平台汇总数据
     *
     * @return
     */
    private AdminPresentDataVO.PlatformSummary getPlatformSummary(String webSite) {
        //订单总额
        OrderExample orderExample = new OrderExample();
        orderExample.setOrderStateIn(OrderConst.ORDER_STATE_20 + "," + OrderConst.ORDER_STATE_30 + "," + OrderConst.ORDER_STATE_40);
        BigDecimal totalSaleAmount = orderModel.getTotalSaleAmount(orderExample);

        //会员总数
        Integer memberCount = memberModel.getMemberCount(new MemberExample());

        //站点会员总数
        MemberExample memberExample =new MemberExample();
        memberExample.setWebSite(webSite);
        Integer webSiteMemberCount =memberModel.getMemberCount(memberExample);

        //店铺总数
        StoreExample storeExample = new StoreExample();
        storeExample.setStateNotEquals(StoreConst.STORE_STATE_DELETE);
        Integer storeCount = storeModel.getStoreCount(storeExample);

        //在售商品总数
        GoodsExample goodsExample = new GoodsExample();
        goodsExample.setState(GoodsConst.GOODS_STATE_UPPER);
        Integer goodsCount = goodsModel.getGoodsCount(goodsExample);

        //站点在售商品总数
        goodsExample = new GoodsExample();
        goodsExample.setWebSite(webSite);
        goodsExample.setState(GoodsConst.GOODS_STATE_UPPER);
        Integer webSiteGoodsCount = goodsModel.getGoodsCount(goodsExample);

        AdminPresentDataVO.PlatformSummary platformSummary = new AdminPresentDataVO.PlatformSummary();
        platformSummary.setOrderPayAmount(totalSaleAmount);
        platformSummary.setMemberNum(memberCount);
        platformSummary.setWebSiteMemberNum(webSiteMemberCount);
        platformSummary.setStoreNum(storeCount);
        platformSummary.setWebSiteStoreNum(storeCount);
        platformSummary.setSaleGoodsNum(goodsCount);
        platformSummary.setWebSiteSaleGoodsNum(webSiteGoodsCount);

        //商品总数
        goodsExample.setWebSite(webSite);
        goodsExample.setState(null);
        goodsExample.setStateNotEquals(GoodsConst.GOODS_STATE_DELETE);
        platformSummary.setGoodsTotalNum(goodsModel.getGoodsCount(goodsExample));

        //下架商品数
        goodsExample.setWebSite(webSite);
        goodsExample.setOnlineTimeAfter(DateUtil.beginOfDay(new Date()));
        goodsExample.setStateIn(GoodsConst.GOODS_STATE_LOWER_BY_STORE + "," + GoodsConst.GOODS_STATE_LOWER_BY_SYSTEM);
        platformSummary.setShelfGoodsNum(goodsModel.getGoodsCount(goodsExample));

        return platformSummary;
    }

    /**
     * 获取今日实时数据
     *
     * @param basicDataBO
     * @return
     */
    private AdminPresentDataVO.PlatformTodaySummary getPlatformTodaySummary(StatsBasicDataBO basicDataBO) {
        AdminPresentDataVO.PlatformTodaySummary todaySummary = new AdminPresentDataVO.PlatformTodaySummary();

        //构造平台统计数据
        PlatformStatsBO platformStatsBO = new PlatformStatsBO();
        PlatformBase platformBase = platformStatsBO.initStats(null, basicDataBO);
        //复制数据
        BeanUtils.copyProperties(platformBase, todaySummary);
        return todaySummary;
    }

    /**
     * 构造商品销售top10
     *
     * @param basicDataBO
     * @return
     */
    private void goodsSaleTop(StatsBasicDataBO basicDataBO, AdminPresentDataVO vo) {
        Collection<GoodsStatsBO> goodsStatsBOS = statsDataUtil.buildGoodsStatsInfo(basicDataBO);

        List<AdminPresentDataVO.PlatformGoodsSale> goodsSaleNumList = new ArrayList<>();//按销量倒序排列
        List<AdminPresentDataVO.PlatformGoodsSale> goodsSaleAmountList = new ArrayList<>();//按销售额倒序排列

        goodsStatsBOS.forEach(goodsStatsBO -> {
            //构造商品统计信息
            GoodsBase goodsBase = goodsStatsBO.initStats(null, basicDataBO.getOrderMap());
            AdminPresentDataVO.PlatformGoodsSale goodsSale = new AdminPresentDataVO.PlatformGoodsSale(goodsBase);
            //销量和销售额二者必须有一个满足条件
            if (goodsSale.getSaleNum() > 0 || goodsSale.getSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                goodsSaleNumList.add(goodsSale);
                goodsSaleAmountList.add(goodsSale);
            }
        });

        //排序
        goodsSaleNumList.sort((o1, o2) -> o2.getSaleNum().compareTo(o1.getSaleNum()));
        goodsSaleAmountList.sort((o1, o2) -> o2.getSaleAmount().compareTo(o1.getSaleAmount()));

        //排行数量，最大10个
        int topNum = Integer.min(10, goodsSaleNumList.size());
        vo.setGoodsSaleNumList(goodsSaleNumList.subList(0, topNum));
        vo.setGoodsSaleAmountList(goodsSaleAmountList.subList(0, topNum));
    }

    /**
     * 构造店铺销售top10
     *
     * @param basicDataBO
     * @return
     */
    private void storeSaleTop(StatsBasicDataBO basicDataBO, AdminPresentDataVO vo) {
        Collection<StoreStatsBO> storeStatsBOS = statsDataUtil.buildStoreStatsInfo(basicDataBO);

        List<AdminPresentDataVO.PlatformStoreSale> storeOrderNumList = new ArrayList<>();//按订单量倒序排列
        List<AdminPresentDataVO.PlatformStoreSale> storeSaleAmountList = new ArrayList<>();//按销售额倒序排列

        storeStatsBOS.forEach(storeStatsBO -> {
            //构造商品统计信息
            StoreBase storeBase = storeStatsBO.initStats(null);
            AdminPresentDataVO.PlatformStoreSale storeSale = new AdminPresentDataVO.PlatformStoreSale(storeBase);
            //订单量和销售额二者必须有一个满足条件
            if (storeSale.getOrderSubmitNum() > 0 || storeSale.getOrderPayAmount().compareTo(BigDecimal.ZERO) > 0) {
                storeOrderNumList.add(storeSale);
                storeSaleAmountList.add(storeSale);
            }
        });

        //排序
        storeOrderNumList.sort((o1, o2) -> o2.getOrderSubmitNum().compareTo(o1.getOrderSubmitNum()));
        storeSaleAmountList.sort((o1, o2) -> o2.getOrderPayAmount().compareTo(o1.getOrderPayAmount()));

        //排行数量，最大10个
        int topNum = Integer.min(10, storeOrderNumList.size());
        vo.setStoreOrderNumList(storeOrderNumList.subList(0, topNum));
        vo.setStoreSaleAmountList(storeSaleAmountList.subList(0, topNum));
    }

    /**
     * 构造商品分类销售top10
     *
     * @param basicDataBO
     * @return
     */
    private void categorySaleTop(StatsBasicDataBO basicDataBO, AdminPresentDataVO vo) {
        Collection<CategoryOrderBO> categoryOrderBOS = statsDataUtil.buildCategoryStatsInfo(basicDataBO);

        List<AdminPresentDataVO.PlatformCategorySale> categorySaleNumList = new ArrayList<>();//按销量倒序排列
        List<AdminPresentDataVO.PlatformCategorySale> categorySaleAmountList = new ArrayList<>();//按销售额倒序排列

        categoryOrderBOS.forEach(categoryOrderBO -> {
            //构造商品统计信息
            CategoryBase categoryBase = categoryOrderBO.initStats(null, basicDataBO.getOrderMap());
            AdminPresentDataVO.PlatformCategorySale categorySale = new AdminPresentDataVO.PlatformCategorySale(categoryBase);
            //销量和销售额二者必须有一个满足条件
            if (categorySale.getSaleNum() > 0 || categorySale.getSaleAmount().compareTo(BigDecimal.ZERO) > 0) {
                categorySaleNumList.add(categorySale);
                categorySaleAmountList.add(categorySale);
            }
        });

        //排序
        categorySaleNumList.sort((o1, o2) -> o2.getSaleNum().compareTo(o1.getSaleNum()));
        categorySaleAmountList.sort((o1, o2) -> o2.getSaleAmount().compareTo(o1.getSaleAmount()));

        //排行数量，最大10个
        int topNum = Integer.min(10, categorySaleNumList.size());
        vo.setCategorySaleNumList(categorySaleNumList.subList(0, topNum));
        vo.setCategorySaleAmountList(categorySaleAmountList.subList(0, topNum));
    }

    /**
     * 分时支付/下单金额
     *
     * @param orderList 时段订单列表
     * @param endTime   截止时间
     * @param vo
     */
    private void timeOrderAmount(List<Order> orderList, Date endTime, AdminPresentDataVO vo) {
        Map<String/*hour*/, AdminPresentDataVO.PlatformTimeAmount> hourSubmitAmountMap = new HashMap<>();
        Map<String/*hour*/, AdminPresentDataVO.PlatformTimeAmount> 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 AdminPresentDataVO.PlatformTimeAmount(hourStr, order.getOrderAmount()));
            }

            if (BrandOrderBO.isOrderPay(order)) {
                //订单已支付，按小时增加支付金额
                if (hourPayAmountMap.containsKey(hourStr)) {
                    hourPayAmountMap.get(hourStr).addAmount(order.getOrderAmount());
                } else {
                    hourPayAmountMap.put(hourStr, new AdminPresentDataVO.PlatformTimeAmount(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 AdminPresentDataVO.PlatformTimeAmount(hourStr, new BigDecimal("0.00"))));
            vo.getOrderPayAmountList().add(hourPayAmountMap.getOrDefault(hourStr, new AdminPresentDataVO.PlatformTimeAmount(hourStr, new BigDecimal("0.00"))));
        }
    }

    /**
     * 分时会员新增
     *
     * @param newMemberList 时段新增会员列表
     * @param endTime       截止时间
     * @param vo
     */
    private void timeNewMemberNum(List<Member> newMemberList, Date endTime, AdminPresentDataVO vo) {
        Map<String/*hour*/, AdminPresentDataVO.PlatformTimeNum> hourNewMemberNumMap = new HashMap<>();

        newMemberList.forEach(member -> {
            //按小时增加新增人数
            int hour = DateUtil.hour(member.getRegisterTime(), true);
            String hourStr = hour > 9 ? hour + ":00" : "0" + hour + ":00";
            if (hourNewMemberNumMap.containsKey(hourStr)) {
                hourNewMemberNumMap.get(hourStr).addNum(1);
            } else {
                hourNewMemberNumMap.put(hourStr, new AdminPresentDataVO.PlatformTimeNum(hourStr, 1));
            }
        });

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

    /**
     * 分时店铺新增
     *
     * @param newStoreList 时段新增店铺列表
     * @param endTime      截止时间
     * @param vo
     */
    private void timeNewStoreNum(List<Store> newStoreList, Date endTime, AdminPresentDataVO vo) {
        Map<String/*hour*/, AdminPresentDataVO.PlatformTimeNum> hourNewStoreNumMap = new HashMap<>();

        newStoreList.forEach(store -> {
            //按小时增加新增店铺数
            int hour = DateUtil.hour(store.getCreateTime(), true);
            String hourStr = hour > 9 ? hour + ":00" : "0" + hour + ":00";
            if (hourNewStoreNumMap.containsKey(hourStr)) {
                hourNewStoreNumMap.get(hourStr).addNum(1);
            } else {
                hourNewStoreNumMap.put(hourStr, new AdminPresentDataVO.PlatformTimeNum(hourStr, 1));
            }
        });

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

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

        memberBehaviorList.forEach(memberBehavior -> {
            if (StatsConstant.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 AdminPresentDataVO.PlatformTimeNum(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 AdminPresentDataVO.PlatformTimeNum(hourStr, 0)));
            vo.getVisitorNumList().add(new AdminPresentDataVO.PlatformTimeNum(hourStr, hourVisitorNumMap.getOrDefault(hourStr, new HashSet<>()).size()));
        }
    }
}
