package com.cyksj.service.mange.statistics.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
import com.cyksj.dto.Result;
import com.cyksj.enums.GatewayResponse;
import com.cyksj.mapper.*;
import com.cyksj.mapper.manage.statistics.*;
import com.cyksj.mapper.mirrorshop.UserMirrorShopMapper;
import com.cyksj.mapper.shop.YhShopMapper;
import com.cyksj.mapper.sys.SysConfigMapper;
import com.cyksj.model.dto.MonthlyUserOrderDetailDto;
import com.cyksj.model.dto.NatureOrderDataDto;
import com.cyksj.model.entity.*;
import com.cyksj.model.excel.ExcelAccountData;
import com.cyksj.model.excel.ExcelMonthOrderData;
import com.cyksj.model.excel.ExcelMonthlyDistributeOrderData;
import com.cyksj.model.excel.ExcelSheetAndData;
import com.cyksj.model.excel.statistics.ExcelAppleOneData;
import com.cyksj.model.excel.statistics.ExcelRealGoodsData;
import com.cyksj.model.excel.statistics.ExcelRegisterAccountData;
import com.cyksj.model.excel.statistics.ExcelStreamingAccountData;
import com.cyksj.model.manage.views.GroupsRelationView;
import com.cyksj.model.manage.views.OrderDonView;
import com.cyksj.model.views.*;
import com.cyksj.service.mange.CmsAccountService;
import com.cyksj.service.mange.statistics.StatisticsDataDayService;
import com.cyksj.service.mange.statistics.StatisticsDataService;
import com.cyksj.service.order.OrderDonService;
import com.ejlchina.searcher.BeanSearcher;
import com.ejlchina.searcher.param.Operator;
import com.ejlchina.searcher.util.MapUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/*
 *项目名: netflix
 *文件名: StatisticsDataServiceImpl
 *创建者: JavaZou
 *创建时间:2022/10/17 14:45
 */
@Service
@RequiredArgsConstructor
public class StatisticsDataServiceImpl implements StatisticsDataService {

	private final OrderDonService orderDonService;

	private final GroupsRelationMapper groupsRelationMapper;

	private final CmsAccountService accountService;

	private final AppleOneDataMapper appleOneDataMapper;

	private final StreamingAccountDataMapper streamingAccountDataMapper;

	private final RealGoodsDataMapper realGoodsDataMapper;

	private final GoodsDonMapper goodsDonMapper;

	private final GoodsDonSkuMapper goodsDonSkuMapper;

	private final BeanSearcher beanSearcher;

	private final StatisticsDataDayService statistics;

	private final GroupsMapper groupsMapper;

	private final OrderDonMapper orderDonMapper;

	private final UserMapper userMapper;

	private final StatisticsUserDataMapper statisticsUserDataMapper;

	private final StatisticsFashionGoodsDataMapper statisticsFashionGoodsDataMapper;

	private final StatisticsExportMapper statisticsExportMapper;

	private final YhShopMapper yhShopMapper;

	private final SysConfigMapper sysConfigMapper;

	private final UserMirrorShopMapper userMirrorShopMapper;

	private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();

	@Override
	public Result<BackgroundDataView> getStatisticsByCondition(Integer type, Long startTime, Long endTime) {
		BackgroundDataView backgroundDataView = new BackgroundDataView();
		Date startDate = null;
		Date endDate = null;
		if (startTime != null) {
			startDate = DateUtil.date(startTime);
		}
		if (endTime != null) {
			endDate = DateUtil.date(endTime);
		}
		switch (type) {
			case 1:
				//流媒体账号
				getStreamingAccountDataView(backgroundDataView, startDate, endDate);
				//appleOne
				getAppleOneDataView(backgroundDataView, startDate, endDate);
				break;
			case 2:
				//实物数据
				getRealGoodsData(backgroundDataView, startDate, endDate);
				break;
			case 3:
				//注册账号数据
				getRegisterAccountData(backgroundDataView, startDate, endDate);
				break;
			case 4:
				//潮玩好物数据
				getFashionGoodsData(backgroundDataView, startDate, endDate);
				break;
			default:
				//流媒体账号
				getStreamingAccountDataView(backgroundDataView, startDate, endDate);
				//appleOne
				getAppleOneDataView(backgroundDataView, startDate, endDate);
				//实物数据
				getRealGoodsData(backgroundDataView, startDate, endDate);
				//注册账号数据
				getRegisterAccountData(backgroundDataView, startDate, endDate);
				//潮玩好物数据
				getFashionGoodsData(backgroundDataView, startDate, endDate);
		}
		return GatewayResponse.SUCCESS.newBuilder().toResult(backgroundDataView);
	}

	private void getFashionGoodsData(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && (DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate) || DateUtil.endOfDay(DateTime.now()).equals(endDate))) {
			List<StatisticsFashionGoodsData> fashionGoodsData = statistics.statisticsFashionGoodsData(startDate, endDate, true);
			List<StatisticsFashionGoodsData> collect = fashionGoodsData.stream().filter(data -> {
				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
					data.setRefundMoney(getRefundMoney(data.getGoodsId(), null, startDate, endDate));
					data.setMoney(data.getMoney().divide(BigDecimal.valueOf(100)));
					return true;
				}
				return false;
			}).collect(Collectors.toList());
			backgroundDataView.setFashionGoodsDataViews(collect);
		} else {
			List<StatisticsFashionGoodsData> fashionGoodsData = statisticsFashionGoodsDataMapper.statisticsFashionGoodsData(startDate, endDate);
			Optional.ofNullable(fashionGoodsData).ifPresent(list -> list.forEach(data -> {
				GoodsDon goodsDon = goodsDonMapper.selectOne(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getId, data.getGoodsId()).last("limit 1"));
				if (goodsDon != null) {
					data.setGoodsTitle(goodsDon.getTitle());
				}
				GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectOne(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getId, data.getSkuId()).last("limit 1"));
				if (goodsDonSku != null) {
					data.setSpecVal(goodsDonSku.getSpecVal());
				}
				data.setRefundMoney(getRefundMoney(null, data.getSkuId(), startDate, endDate));
			}));
			backgroundDataView.setFashionGoodsDataViews(fashionGoodsData);
		}
	}

	/**
	 * 注册账号数据
	 */
	private void getRegisterAccountData(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && (DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate) || DateUtil.endOfDay(DateTime.now()).equals(endDate))) {
			List<RegisterAccountData> registerAccountData = statistics.statisticsRegisterAccountData(startDate, endDate, true);
			List<RegisterAccountData> collect = registerAccountData.stream().filter(data -> {
				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
					data.setMoney(data.getMoney().divide(BigDecimal.valueOf(100)));
					data.setRefundMoney(data.getRefundMoney() == null ? BigDecimal.ZERO : data.getRefundMoney().divide(BigDecimal.valueOf(100)));
					return true;
				}
				return false;
			}).collect(Collectors.toList());
			backgroundDataView.setRegisterAccountDataViews(collect);
		} else {
			List<RegisterAccountData> registerAccountData = realGoodsDataMapper.statisticsRegisterAccountData(startDate, endDate);
			backgroundDataView.setRegisterAccountDataViews(registerAccountData);
		}
	}

	@Override
	public IPage<ExpiredAccountDataView> getExpiredAccountView(Boolean isCorpWx, String customerService, Long goodsId, Long skuId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, Long startTime, Long endTime, Long start, Long limit) {
		String startDate = null;
		String endDate = null;
		if (startTime != null) {
			startDate = DateTime.of(startTime).toString();
		}
		if (endTime != null) {
			endDate = DateTime.of(endTime).toString();
		}
		IPage<ExpiredAccountDataView> expiredAccountDataViews = accountService.getExpiredAccountView(isCorpWx, customerService, goodsId, skuId, account, renewStatus, handleStatus, cnAccount, usAccount, userId, startDate, endDate, DateTime.now().toString(), start, limit);
		return expiredAccountDataViews;
	}

	@Override
	public List<ExcelAccountData> getExpiredAccountViewNoPage(Boolean isCorpWx, String customerService, Long goodsId, Long skuId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, Long startTime, Long endTime) {
		String startDate = null;
		String endDate = null;
		if (startTime != null) {
			startDate = DateTime.of(startTime).toString();
		}
		if (endTime != null) {
			endDate = DateTime.of(endTime).toString();
		}
		List<ExcelAccountData> expiredAccountDataViews = accountService.getExpiredAccountViewNoPage(isCorpWx, customerService, goodsId, skuId, account, renewStatus, handleStatus, cnAccount, usAccount, userId, startDate, endDate, DateTime.now().toString());
		return expiredAccountDataViews;
	}

	@Override
	public BackgroundDataView getTitleData() {
		BackgroundDataView backgroundDataView = new BackgroundDataView();
		Number waitingRegisterNum = beanSearcher.searchCount(RegisterOrderDon.class, MapUtils.builder()
				.field(RegisterOrderDon::getStatus, RegisterOrderDon.Status.hasPayment.name()).op(Operator.Equal)
				.onlySelect(RegisterOrderDon::getId).build());
		backgroundDataView.setWaitingRegisterNum(waitingRegisterNum.intValue());
		Number errorRegisterNum = beanSearcher.searchCount(RegisterOrderDon.class, MapUtils.builder()
				.field(RegisterOrderDon::getStatus, RegisterOrderDon.Status.error.name()).op(Operator.Equal)
				.onlySelect(RegisterOrderDon::getId)
				.build());
		backgroundDataView.setFailRegisterNum(errorRegisterNum.intValue());

		//netflix
		GoodsDonSkuView goodsDonSkuView = beanSearcher.searchFirst(GoodsDonSkuView.class, MapUtils.builder()
				.field(GoodsDonSkuView::getGoodsTitle, "Netflix")
				.field(GoodsDonSkuView::getSpecVal, "月付").op(Operator.Contain).build());
		Long skuId = goodsDonSkuView.getSkuId();

		Integer numOfMonthNetflix = groupsMapper.selectCount(Wrappers.lambdaQuery(GroupsTrips.class)
				.eq(GroupsTrips::getSkuId, skuId));
		backgroundDataView.setNumOfMonthNetflix(numOfMonthNetflix);


		Integer numOfMonthEmptyRelationNetflix = beanSearcher.searchCount(GroupsRelationView.class, MapUtils.builder()
				.field(GroupsRelationView::getSkuId, skuId)
				.field(GroupsRelationView::getUserId, 0)
				.build()).intValue();
		backgroundDataView.setNumOfMonthEmptyRelationNetflix(numOfMonthEmptyRelationNetflix);

		Integer numOfMonthEmptyTripsNetflix = groupsMapper.selectEmptyNetflixTrips(skuId);
		backgroundDataView.setNumOfMonthEmptyTripsNetflix(numOfMonthEmptyTripsNetflix);
		Number number = beanSearcher.searchCount(OrderDonView.class, MapUtils.builder().field(OrderDonView::getType, Constant.realGoodsType).op(Operator.InList)
				.field(OrderDonView::getStatus, OrderDon.Status.hasPayment.name())
				.build());
		backgroundDataView.setWaitingSendRealOrder(number.intValue());
		return backgroundDataView;
	}

	@Override
	public Result<String> updateRenewStatus(Long relationId) {
		GroupsRelation groupsRelation = groupsRelationMapper.selectById(relationId);
		groupsRelation.setRenewStatus(!groupsRelation.getRenewStatus());
		groupsRelationMapper.updateById(groupsRelation);
		return GatewayResponse.SUCCESS.newBuilder().toResult("续约意愿状态变更成功");
	}

	@Override
	public Result<String> updateHandleStatus(Long relationId) {
		GroupsRelation groupsRelation = groupsRelationMapper.selectById(relationId);
		groupsRelation.setIsHandle(!groupsRelation.getIsHandle());
		groupsRelationMapper.updateById(groupsRelation);
		return GatewayResponse.SUCCESS.newBuilder().toResult("处理状态变更成功");
	}

	@Override
	public List<ExcelSheetAndData> exportStatisticsDataByType(Integer type, Long startTime, Long endTime) {
		String startDate = null;
		String endDate = null;
		if (type == null) type = 0;
		if (startTime != null) {
			startDate = DateTime.of(startTime).toString();
		}
		if (endTime != null) {
			endDate = DateTime.of(endTime).toString();
		}
		List<ExcelSheetAndData> excelSheetDataList = new ArrayList<>();
		switch (type) {
			case 1:
				exportAppleOneData(excelSheetDataList, startDate, endDate);
				break;
			case 2:
				exportStreamingAccountData(excelSheetDataList, startDate, endDate);
				break;
			case 3:
				exportRealGoodsData(excelSheetDataList, startDate, endDate);
				break;
			case 4:
				exportFashionData(excelSheetDataList, startDate, endDate);
				break;
			case 5:
				exportRegisterData(excelSheetDataList, startDate, endDate);
				break;
			default:
				exportAllTypeData(excelSheetDataList, startDate, endDate);
		}
		return excelSheetDataList;
	}

	@Override
	public List<ExcelSheetAndData> exportMonthlyData(Long startTime, Long endTime) {
		List<ExcelSheetAndData> excelSheetDataList = new ArrayList<>();
		String startDate = null;
		String endDate = null;
		if (startTime != null) {
			startDate = DateTime.of(startTime).toString();
		}
		if (endTime != null) {
			endDate = DateTime.of(endTime).toString();
		}
		final String f_st = startDate;
		final String f_et = endDate;
		CountDownLatch countDownLatch = new CountDownLatch(2);
		//业务订单数
		TASK_POOL.execute(() -> {
			try {
				exportBusinessMonthlyData(excelSheetDataList, startTime, endTime);
			} finally {
				countDownLatch.countDown();
			}
		});
		//分销类型订单数据
		TASK_POOL.execute(() -> {
			try {
				exportDistributeMonthlyData(excelSheetDataList, f_st, f_et);
			} finally {
				countDownLatch.countDown();
			}
		});
		try {
			countDownLatch.await();
		} catch (InterruptedException e) {
		}
		return excelSheetDataList;
	}

	@Override
	public Result<BackgroundDataView> getStatisticsHeader(Long startTime, Long endTime) {
		Date startDate = null;
		Date endDate = null;
		if (startTime != null) {
			startDate = DateUtil.date(startTime);
		}
		if (endTime != null) {
			endDate = DateUtil.date(endTime);
		}
		BackgroundDataView backgroundDataView = getHeaderData(startDate, endDate);
		return GatewayResponse.SUCCESS.newBuilder().toResult(backgroundDataView);
	}

	@Override
	public void yhShopDistribute(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
		//店铺数量
		//注册用户
		Map<String, Object> yhShopDetail = yhShopMapper.selectYhShopDetail(startDate, endDate);
		backgroundDataView.setNumOfYhShop(Integer.parseInt(yhShopDetail.get("numOfYhShop").toString()));
		backgroundDataView.setNumOfYhShopRegisterUser(Integer.parseInt(yhShopDetail.get("numOfRegisterYhShopUser").toString()));
		//销售单数
		//销售金额
		Map<String, Object> yhShopOrderDetail = orderDonMapper.selectYhShopDistributeOrderDetail(startDate, endDate);
		backgroundDataView.setNumOfYhShopDsOrders(Integer.parseInt(yhShopOrderDetail.get("numOfDsOrder").toString()));
		backgroundDataView.setYhShopAmount(BigDecimal.valueOf(Long.parseLong(yhShopOrderDetail.get("dsMoney").toString())).divide(BigDecimal.valueOf(100)));
		//提成金额
		BigDecimal yhShopTakeMoney = yhShopMapper.selectYhShopTakeMoney(startDate, endDate);
		backgroundDataView.setYhShopTakeMoney(yhShopTakeMoney.divide(BigDecimal.valueOf(100)));


		Map<String,Object> yhShopApplyDetail = yhShopMapper.selectYhShopApplyMoney(startDate, endDate);
		//已提现
		backgroundDataView.setDistributeGotMoney(BigDecimal.valueOf(Long.parseLong(yhShopApplyDetail.get("s").toString())).divide(BigDecimal.valueOf(100)));
		//待审核
		backgroundDataView.setDistributeVerifyingMoney(BigDecimal.valueOf(Long.parseLong(yhShopApplyDetail.get("vf").toString())).divide(BigDecimal.valueOf(100)));
	}

	public void exportAllTypeData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
		CountDownLatch latch = new CountDownLatch(2);
		TASK_POOL.execute(() -> {
			try {
				exportStreamingAccountData(excelSheetDataList, startDate, endDate);
			} finally {
				latch.countDown();
			}
		});
		TASK_POOL.execute(() -> {
			try {
				exportRealGoodsData(excelSheetDataList, startDate, endDate);
			} finally {
				latch.countDown();
			}
		});
		exportAppleOneData(excelSheetDataList, startDate, endDate);
		exportFashionData(excelSheetDataList, startDate, endDate);
		exportRegisterData(excelSheetDataList, startDate, endDate);
		try {
			latch.await();
		} catch (InterruptedException e) {
		}
	}

	@Override
	public GroupsDataStatisticsView getGroupsData(Long startTime, Long endTime, Integer type, Boolean isGeneral) throws Exception {
		GroupsDataStatisticsView groupsDataStatisticsView = new GroupsDataStatisticsView();
		String startDate = null;
		String endDate = null;
		if (startTime != null) {
			startDate = DateTime.of(startTime).toString();
		}
		if (endTime != null) {
			endDate = DateTime.of(endTime).toString();
		}
		if (startDate == null) {
			startDate = DateUtil.beginOfMonth(DateTime.now()).toString();
		}
		switch (type) {
			case 1:
				getNatureOrderData(groupsDataStatisticsView, startDate, endDate);
				break;
			case 2:
				getCategoryOrderData(groupsDataStatisticsView, startDate, endDate);
				break;
			case 3:
				getGroupsOrderCategoryData(groupsDataStatisticsView, startDate, endDate);
				break;
			case 4:
				getRenewOrderData(groupsDataStatisticsView, startDate, endDate);
				break;
			case 5:
				getUnbindChannelOrderData(groupsDataStatisticsView, startDate, endDate);
				break;
			case 6:
				getRealGoodsSourceData(groupsDataStatisticsView, isGeneral, startDate, endDate);
				break;
			default:
				getSynthesisData(groupsDataStatisticsView, isGeneral, startDate, endDate);
		}
		return groupsDataStatisticsView;
	}

	@Override
	public void userMirrorShopDistribute(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
		//店铺数量
		//注册用户
		Map<String, Object> yhShopDetail = userMirrorShopMapper.selectUserMIrrorShopDetail(startDate, endDate);
		backgroundDataView.setNumOfYhShop(Integer.parseInt(yhShopDetail.get("numOfYhShop").toString()));
		backgroundDataView.setNumOfYhShopRegisterUser(Integer.parseInt(yhShopDetail.get("numOfRegisterYhShopUser").toString()));
		//销售单数
		//销售金额
		Map<String, Object> yhShopOrderDetail = orderDonMapper.selectUserMIrrorShopDistributeOrderDetail(startDate, endDate);
		backgroundDataView.setNumOfYhShopDsOrders(Integer.parseInt(yhShopOrderDetail.get("numOfDsOrder").toString()));
		backgroundDataView.setYhShopAmount(BigDecimal.valueOf(Long.parseLong(yhShopOrderDetail.get("dsMoney").toString())).divide(BigDecimal.valueOf(100)));
		//提成金额
		BigDecimal yhShopTakeMoney = userMirrorShopMapper.selectUserMirrorShopTakeMoney(startDate, endDate);
		backgroundDataView.setYhShopTakeMoney(yhShopTakeMoney.divide(BigDecimal.valueOf(100)));


		Map<String, Object> yhShopApplyDetail = userMirrorShopMapper.selectUserMirrorShopApplyMoney(startDate, endDate);
		//已提现
		backgroundDataView.setDistributeGotMoney(BigDecimal.valueOf(Long.parseLong(yhShopApplyDetail.get("s").toString())).divide(BigDecimal.valueOf(100)));
		//待审核
		backgroundDataView.setDistributeVerifyingMoney(BigDecimal.valueOf(Long.parseLong(yhShopApplyDetail.get("vf").toString())).divide(BigDecimal.valueOf(100)));
	}

	private void getUnbindChannelOrderData(GroupsDataStatisticsView groupsDataStatisticsView, String startDate, String endDate) {
		//解绑渠道
		//流媒体
		BigDecimal unBIndGroupsStreamingMoney = Optional.ofNullable(statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(4, null, 2l, startDate, endDate, true)).orElse(BigDecimal.ZERO);
		// AI销售金额
		BigDecimal unBIndGroupsAiOrderMoney = Optional.ofNullable(statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(4, null, 1l, startDate, endDate, true)).orElse(BigDecimal.ZERO);
		//设备销售金额
		BigDecimal unBIndGroupsEpOrderMoney = Optional.ofNullable(statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(4, 2, null, startDate, endDate, true)).orElse(BigDecimal.ZERO);
		BigDecimal wholesaleOrderMoney = Optional.ofNullable(statisticsExportMapper.getWholesaleOrderMoney(startDate, endDate)).orElse(BigDecimal.ZERO);
		groupsDataStatisticsView.setUnBIndGroupsStreamingMoney(unBIndGroupsStreamingMoney);
		groupsDataStatisticsView.setUnBIndGroupsAiOrderMoney(unBIndGroupsAiOrderMoney);
		groupsDataStatisticsView.setUnBIndGroupsEpOrderMoney(unBIndGroupsEpOrderMoney);
		groupsDataStatisticsView.setWholesaleOrderMoney(wholesaleOrderMoney);
	}

	public void getNatureOrderData(GroupsDataStatisticsView groupsDataStatisticsView, String startDate, String endDate) {
		List<NatureOrderDataDto> orderDataList = statisticsExportMapper.getGroupsOrderData(startDate, endDate);
		orderDataList.forEach(data -> {
			BigDecimal money = data.getMoney();
			if (data.getType() == 1) {
				groupsDataStatisticsView.setNatureMoney(money);
				return;
			}
			if (data.getType() == 2) {
				groupsDataStatisticsView.setPersonalMoney(money);
				return;
			}
			if (data.getType() == 3) {
				groupsDataStatisticsView.setChannelMoney(money);
			}
			if (data.getType() == 4) {
				groupsDataStatisticsView.setUnBindChannelMoney(money);
			}
		});
		if (groupsDataStatisticsView.getNatureMoney() == null) {
			groupsDataStatisticsView.setNatureMoney(BigDecimal.ZERO);
		}
		if (groupsDataStatisticsView.getPersonalMoney() == null) {
			groupsDataStatisticsView.setPersonalMoney(BigDecimal.ZERO);
		}
		if (groupsDataStatisticsView.getChannelMoney() == null) {
			groupsDataStatisticsView.setChannelMoney(BigDecimal.ZERO);
		}
	}

	public void getCategoryOrderData(GroupsDataStatisticsView groupsDataStatisticsView, String startDate, String endDate) {
		BigDecimal natureStreamingMoney = Optional.ofNullable(statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(1, null, 2l, startDate, endDate, true)).orElse(BigDecimal.ZERO);
		// AI销售金额
		BigDecimal natureAiOrderMoney = Optional.ofNullable(statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(1, null, 1l, startDate, endDate, true)).orElse(BigDecimal.ZERO);
		//设备销售金额
		BigDecimal natureEpOrderMoney = Optional.ofNullable(statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(1, 2, null, startDate, endDate, true)).orElse(BigDecimal.ZERO);
		groupsDataStatisticsView.setNatureStreamingMoney(natureStreamingMoney);
		groupsDataStatisticsView.setNatureAiOrderMoney(natureAiOrderMoney);
		groupsDataStatisticsView.setNatureEpOrderMoney(natureEpOrderMoney);
	}

	public void getGroupsOrderCategoryData(GroupsDataStatisticsView groupsDataStatisticsView, String startDate, String endDate) {
		//渠道商+个人分销
		//流媒体
		BigDecimal groupsStreamingMoney = Optional.ofNullable(statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(2, null, 2l, startDate, endDate, true)).orElse(BigDecimal.ZERO);
		// AI销售金额
		BigDecimal groupsAiOrderMoney = Optional.ofNullable(statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(2, null, 1l, startDate, endDate, true)).orElse(BigDecimal.ZERO);
		//设备销售金额
		BigDecimal groupsEpOrderMoney = Optional.ofNullable(statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(2, 2, null, startDate, endDate, true)).orElse(BigDecimal.ZERO);
		groupsDataStatisticsView.setGroupsStreamingMoney(groupsStreamingMoney);
		groupsDataStatisticsView.setGroupsAiOrderMoney(groupsAiOrderMoney);
		groupsDataStatisticsView.setGroupsEpOrderMoney(groupsEpOrderMoney);
	}

	public void getRenewOrderData(GroupsDataStatisticsView groupsDataStatisticsView, String startDate, String endDate) {
		BigDecimal oriRenewOrderMoney = Optional.ofNullable(orderDonMapper.getOriRenewOrderMoney(startDate, endDate)).orElse(BigDecimal.ZERO);
		BigDecimal clearRenewOrderMoney = Optional.ofNullable(orderDonMapper.getClearRenewOrderMoney(startDate, endDate)).orElse(BigDecimal.ZERO);
		groupsDataStatisticsView.setRenewOrderMoney(oriRenewOrderMoney.add(clearRenewOrderMoney));
		BigDecimal totalMoney = Optional.ofNullable(orderDonMapper.getTotalMoney(startDate, endDate)).orElse(BigDecimal.ZERO);
		groupsDataStatisticsView.setNewBuyOrderMoney(totalMoney.subtract(groupsDataStatisticsView.getRenewOrderMoney()));
	}

	public void getSynthesisData(GroupsDataStatisticsView groupsDataStatisticsView, Boolean isGeneral, String startDate, String endDate) throws Exception {
		CountDownLatch latch = new CountDownLatch(2);
		TASK_POOL.execute(() -> {
			try {
				getNatureOrderData(groupsDataStatisticsView, startDate, endDate);
				getCategoryOrderData(groupsDataStatisticsView, startDate, endDate);
			} finally {
				latch.countDown();
			}
		});
		TASK_POOL.execute(() -> {
			try {
				getGroupsOrderCategoryData(groupsDataStatisticsView, startDate, endDate);
				getRenewOrderData(groupsDataStatisticsView, startDate, endDate);
				getUnbindChannelOrderData(groupsDataStatisticsView, startDate, endDate);
				getRealGoodsSourceData(groupsDataStatisticsView, isGeneral, startDate, endDate);
			} finally {
				latch.countDown();
			}
		});
		latch.await();
	}

	private void getRealGoodsSourceData(GroupsDataStatisticsView groupsDataStatisticsView, Boolean isGeneral, String startDate, String endDate) {
		List<RealGoodsSourceData> realGoodsSourceDataList = orderDonMapper.getRealGoodsSourceData(isGeneral, startDate, endDate);
		Map<String, List<RealGoodsSourceData>> collect = realGoodsSourceDataList.stream().collect(Collectors.groupingBy(RealGoodsSourceData::getLabelSource));
		OrderDon.LabelSource[] values = OrderDon.LabelSource.values();
		BigDecimal zero = BigDecimal.ZERO;
		Integer orders = 0;
		RealGoodsSourceData realGoodsSourceData = null;
		for (OrderDon.LabelSource sysSource : values) {
			if (collect.get(sysSource.name()) == null) {
				realGoodsSourceData = new RealGoodsSourceData(sysSource.name(), orders, zero);
				realGoodsSourceDataList.add(realGoodsSourceData);
			}
		}
		groupsDataStatisticsView.setRealGoodsSourceDataList(realGoodsSourceDataList);
	}

	private void exportBusinessMonthlyData(List<ExcelSheetAndData> excelSheetDataList, Long startTime, Long endTime) {
		//月付、季付、年付
		Long nf_goodsId = 1l;
		Long gpt_goodsId = 18l;
		Long mj_goodsId = 26l;
		DateTime thisMonth = DateTime.of(startTime);
		DateTime nextMonth = DateUtil.offsetMonth(thisMonth, 1);
		String lastMonth = DateUtil.offsetMonth(thisMonth, -1).toDateStr();
		//前两个月
		String lastTwoMonth = DateUtil.offsetMonth(thisMonth, -2).toDateStr();
		//前三个月
		String lastThreeMonth = DateUtil.offsetMonth(thisMonth, -3).toDateStr();
		//前十一个月
		String lastElevMonth = DateUtil.offsetMonth(thisMonth, -11).toDateStr();
		//前十二个月
		String lastYearMonth = DateUtil.offsetMonth(thisMonth, -12).toDateStr();
		//奈飞当月过期人数
		Integer monthNfExNumOfUser = statisticsExportMapper.getMonthNfExNumOfUser(nf_goodsId, lastYearMonth, lastElevMonth, lastThreeMonth, lastTwoMonth, lastMonth, thisMonth.toDateStr());
		//奈飞 A主动续费
		Integer monthNfExRenewNumOfUser = statisticsExportMapper.getMonthNfExNumOfUserByType(nf_goodsId, 2, lastYearMonth, lastElevMonth, lastThreeMonth, lastTwoMonth, lastMonth, thisMonth.toDateStr(), nextMonth.toDateStr());
		//奈飞 A再次购买
		Integer monthNfExRePayNumOfUser = statisticsExportMapper.getMonthNfExNumOfUserByType(nf_goodsId, 1, lastYearMonth, lastElevMonth, lastThreeMonth, lastTwoMonth, lastMonth, thisMonth.toDateStr(), nextMonth.toDateStr());
		//奈飞 非当月到期 主动续费
		//当月续费人数
		Integer monthNfRenewNumOfUser = statisticsExportMapper.getMonthNfRenewNumOfUser(nf_goodsId, thisMonth, nextMonth);
		Integer monthNfNoExRenewNumOfUser = monthNfRenewNumOfUser - monthNfExRenewNumOfUser;

		//奈飞超期购买 中间隔断一个月购买的用户数
		Integer overNfPayNumOfUser = statisticsExportMapper.getOverPayByGoodsId(nf_goodsId, null, lastMonth, thisMonth, nextMonth);

		//Ai Gpt月付
		List<Long> gptMonthSkuId = statisticsExportMapper.getAiMonthPlus(18l);
		//Ai类gptplus当月到期用户数
		Integer monthAiGptExNumOfUser = statisticsExportMapper.getMonthAiExNumOfUser(gptMonthSkuId, lastMonth, thisMonth);
		//AiGpt月付 A主动续费
		Integer monthAiGptExRenewNumOfUser = statisticsExportMapper.getMonthAiExNumOfUserByType(gptMonthSkuId, 2, lastMonth, thisMonth, nextMonth.toDateStr());
		//AiGpt月付 再次购买
		Integer monthAiGptExRePayNumOfUser = statisticsExportMapper.getMonthAiExNumOfUserByType(gptMonthSkuId, 1, lastMonth, thisMonth, nextMonth.toDateStr());
		//AiGpt当月续费人数
		Integer monthAiGptRenewNumOfUser = statisticsExportMapper.getMonthAiRenewNumOfUser(gptMonthSkuId, thisMonth, nextMonth);
		//非当月 续费人数
		Integer monthAiGptNoExRenewNumOfUser = monthAiGptRenewNumOfUser - monthAiGptExRenewNumOfUser;
		//超期购买 中间隔断一个月购买的用户数
		Integer overGptPayNumOfUser = statisticsExportMapper.getOverPayByGoodsId(null, gptMonthSkuId, lastMonth, thisMonth, nextMonth);

		//Ai midjourney 月付
		List<Long> midJourneyMonthSkuId = statisticsExportMapper.getAiMonthPlus(26l);
		Integer monthAiMidExNumOfUser = statisticsExportMapper.getMonthAiExNumOfUser(midJourneyMonthSkuId, lastMonth, thisMonth);
		//Ai midjourney月付 A主动续费
		Integer monthAiMidExRenewNumOfUser = statisticsExportMapper.getMonthAiExNumOfUserByType(midJourneyMonthSkuId, 2, lastMonth, thisMonth, nextMonth.toDateStr());
		//Ai midjourney月付 再次购买
		Integer monthAiMidExRePayNumOfUser = statisticsExportMapper.getMonthAiExNumOfUserByType(midJourneyMonthSkuId, 1, lastMonth, thisMonth, nextMonth.toDateStr());
		//Ai midjourney当月续费人数
		Integer monthAiMidRenewNumOfUser = statisticsExportMapper.getMonthAiRenewNumOfUser(midJourneyMonthSkuId, thisMonth, nextMonth);
		//非当月 midjourney续费人数
		Integer monthAiMidNoExRenewNumOfUser = monthAiMidRenewNumOfUser - monthAiMidExRenewNumOfUser;
		//超期购买 中间隔断一个月购买的用户数
		Integer overMjPayNumOfUser = statisticsExportMapper.getOverPayByGoodsId(null, midJourneyMonthSkuId, lastMonth, thisMonth, nextMonth);

		//油管年付
		Long ybGoodsId = 5l;
		Integer youtubeNumOfRenewals = statisticsExportMapper.getYearNumOfRenewalsByGoodsId(ybGoodsId, lastElevMonth, lastYearMonth);
		//实际续费人数
		Integer youtubeActualNumberOfRenewals = statisticsExportMapper.getActualNumberOfRenewalsByGoodsId(ybGoodsId, lastElevMonth, lastYearMonth);
		//声破天 续费数据
		Long spGoodsId = 4l;
		Integer spotifyNumOfRenewals = statisticsExportMapper.getYearNumOfRenewalsByGoodsId(spGoodsId, lastElevMonth, lastYearMonth);
		//实际续费人数
		Integer spotifyActualNumberOfRenewals = statisticsExportMapper.getActualNumberOfRenewalsByGoodsId(spGoodsId, lastElevMonth, lastYearMonth);
		//迪士尼年付
		Long dsGoodsId = 3l;
		Integer disneyNumOfRenewals = statisticsExportMapper.getYearNumOfRenewalsByGoodsId(dsGoodsId, lastElevMonth, lastYearMonth);
		//实际续费人数
		Integer disneyActualNumberOfRenewals = statisticsExportMapper.getActualNumberOfRenewalsByGoodsId(dsGoodsId, lastElevMonth, lastYearMonth);

		//流媒体当月首单
		Integer monthStreamingNewNumOfUser = statisticsExportMapper.getMonthStreamingNewNumOfUser(thisMonth, nextMonth);

		//流媒体 A中第二单 为任意产品
		Integer monthStreamingNewPayOtherNumOfUser = statisticsExportMapper.getMonthStreamingNewPayOtherNumOfUser(thisMonth, nextMonth);
		//流媒体 A中第二单 为Ai产品
		Integer monthStreamingNewPayAiNumOfUser = statisticsExportMapper.getMonthStreamingNewPayAiNumOfUser(thisMonth, nextMonth);

		//AI类复购
		//Ai当月购买新用户数
		Integer monthAiNewNumOfUser = statisticsExportMapper.getMonthAiNewNumOfUser(thisMonth, nextMonth);
		//Ai A中第二单 为任意产品
		Integer monthAiNewPayOtherNumOfUser = statisticsExportMapper.getMonthAiNewPayOtherNumOfUser(thisMonth, nextMonth);
		//Ai A中第二单 为流媒体
		Integer monthAiNewPayStreamingNumOfUser = statisticsExportMapper.getMonthAiNewPayStreamingNumOfUser(thisMonth, nextMonth);

		//用户维度 订单数据
		List<MonthlyUserOrderDetailDto> monthlyUserOrderDetails = statisticsExportMapper.getMonthlyUserOrderDetail(thisMonth, nextMonth);
		Integer monthlyNewUserOrders = 0;
		BigDecimal monthlyNewUserOrdersMoney = BigDecimal.ZERO;
		Integer monthlyBeforeUserOrders = 0;
		BigDecimal monthlyBeforeUserOrdersMoney = BigDecimal.ZERO;
		for (MonthlyUserOrderDetailDto monthlyUserOrderDetail : monthlyUserOrderDetails) {
			BigDecimal money = monthlyUserOrderDetail.getMoney();
			Integer orders = monthlyUserOrderDetail.getOrders();
			//上月
			if (monthlyUserOrderDetail.getType() == 1) {
				monthlyBeforeUserOrders = orders;
				monthlyBeforeUserOrdersMoney = money;
			} else {
				monthlyNewUserOrders = orders;
				monthlyNewUserOrdersMoney = money;
			}
		}

//		//历史复购 AI、奈飞车票人数 以及交叉
//		Integer nfTicketNumOfUser = statisticsExportMapper.getNfTicketNumOfUser(1l);
//
//		Integer aiTicketNumOfUser = statisticsExportMapper.getAiTicketNumOfUser();
//
//		Integer nfAiTicketNumOfUser = statisticsExportMapper.getNfAiTicketNumOfUser(1l);
//		//私域
//		//首单流媒体用户数
//		Integer monthPrivateStreamingNumOfUser = statisticsExportMapper.getMonthPrivateCorpNumOfUser(null, 2);
//		//首单Ai用户数
//		Integer monthPrivateAiNumOfUser = statisticsExportMapper.getMonthPrivateCorpNumOfUser(null, 1);
//		//首单实物设备
//		Integer monthPrivateEqNumOfUser = statisticsExportMapper.getMonthPrivateCorpNumOfUser(2, null);
		ExcelMonthOrderData excelMonthOrderData = new ExcelMonthOrderData()
				.setMonthNfExNumOfUser(monthNfExNumOfUser)
				.setMonthNfExRenewNumOfUser(monthNfExRenewNumOfUser)
				.setMonthNfExRePayNumOfUser(monthNfExRePayNumOfUser)
				.setMonthNfNoExRenewNumOfUser(monthNfNoExRenewNumOfUser)
				.setOverNfPayNumOfUser(overNfPayNumOfUser)
				.setMonthAiGptExNumOfUser(monthAiGptExNumOfUser)
				.setMonthAiGptExRenewNumOfUser(monthAiGptExRenewNumOfUser)
				.setMonthAiGptExRePayNumOfUser(monthAiGptExRePayNumOfUser)
				.setMonthAiGptNoExRenewNumOfUser(monthAiGptNoExRenewNumOfUser)
				.setOverGptPayNumOfUser(overGptPayNumOfUser)
				.setMonthAiMidExNumOfUser(monthAiMidExNumOfUser)
				.setMonthAiMidExRenewNumOfUser(monthAiMidExRenewNumOfUser)
				.setMonthAiMidExRePayNumOfUser(monthAiMidExRePayNumOfUser)
				.setMonthAiMidNoExRenewNumOfUser(monthAiMidNoExRenewNumOfUser)
				.setOverMidPayNumOfUser(overMjPayNumOfUser)
				.setMonthStreamingNewNumOfUser(monthStreamingNewNumOfUser)
				.setMonthStreamingNewPayOtherNumOfUser(monthStreamingNewPayOtherNumOfUser)
				.setMonthStreamingNewPayAiNumOfUser(monthStreamingNewPayAiNumOfUser)
				.setMonthAiNewNumOfUser(monthAiNewNumOfUser)
				.setMonthAiNewPayOtherNumOfUser(monthAiNewPayOtherNumOfUser)
				.setMonthAiNewPayStreamingNumOfUser(monthAiNewPayStreamingNumOfUser)
				.setMonthlyNewUserOrders(monthlyNewUserOrders)
				.setMonthlyNewUserOrdersMoney(monthlyNewUserOrdersMoney)
				.setMonthlyBeforeUserOrders(monthlyBeforeUserOrders)
				.setMonthlyBeforeUserOrdersMoney(monthlyBeforeUserOrdersMoney)
				.setYoutubeNumOfRenewals(youtubeNumOfRenewals)
				.setYoutubeActualNumberOfRenewals(youtubeActualNumberOfRenewals)
				.setSpotifyNumOfRenewals(spotifyNumOfRenewals)
				.setSpotifyActualNumberOfRenewals(spotifyActualNumberOfRenewals)
				.setDisneyNumOfRenewals(disneyNumOfRenewals)
				.setDisneyActualNumberOfRenewals(disneyActualNumberOfRenewals)
				;
//				.setNfTicketNumOfUser(nfTicketNumOfUser)
//				.setAiTicketNumOfUser(aiTicketNumOfUser)
//				.setNfAiTicketNumOfUser(nfAiTicketNumOfUser)
//				.setMonthPrivateStreamingNumOfUser(monthPrivateStreamingNumOfUser)
//				.setMonthPrivateAiNumOfUser(monthPrivateAiNumOfUser)
//				.setMonthPrivateEqNumOfUser(monthPrivateEqNumOfUser);
		excelSheetDataList.add(new ExcelSheetAndData("每月订单业务数据", List.of(excelMonthOrderData), ExcelMonthOrderData.class, 1));
	}

	private void exportDistributeMonthlyData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
		ExcelMonthlyDistributeOrderData excelMonthlyDistributeOrderData = new ExcelMonthlyDistributeOrderData();
		//渠道分销数据
		//自然渠道销售金额
		BigDecimal monthAmountOfOrder = statisticsExportMapper.getMonthAmountOfOrderByType(1, startDate, endDate);
		excelMonthlyDistributeOrderData.setMonthAmountOfOrder(monthAmountOfOrder);
		//个人渠道销售金额
		BigDecimal monthDsAmountOfOrder = statisticsExportMapper.getMonthAmountOfOrderByType(2, startDate, endDate);
		excelMonthlyDistributeOrderData.setMonthDsAmountOfOrder(monthDsAmountOfOrder);
		//渠道商销售金额
		BigDecimal monthDsFAmountOfOrder = statisticsExportMapper.getMonthAmountOfOrderByType(3, startDate, endDate);
		excelMonthlyDistributeOrderData.setMonthDsFAmountOfOrder(monthDsFAmountOfOrder);
		//自然渠道
		//流媒体
		BigDecimal monthStreamingAmountOfOrder = statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(1, null, 2l, startDate, endDate,null);
		excelMonthlyDistributeOrderData.setMonthStreamingAmountOfOrder(monthStreamingAmountOfOrder);
		// AI销售金额
		BigDecimal monthAiAmountOfOrder = statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(1, null, 1l, startDate, endDate,null);
		excelMonthlyDistributeOrderData.setMonthAiAmountOfOrder(monthAiAmountOfOrder);
		//设备销售金额
		BigDecimal monthOfEqAmountOfOrder = statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(1, 2, null, startDate, endDate,null);
		excelMonthlyDistributeOrderData.setMonthOfEqAmountOfOrder(monthOfEqAmountOfOrder);
		//渠道商+个人分销
		//流媒体
		BigDecimal monthOfSpecStreamingAmountOfOrder = statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(2, null, 2l, startDate, endDate,null);
		excelMonthlyDistributeOrderData.setMonthOfSpecStreamingAmountOfOrder(monthOfSpecStreamingAmountOfOrder);
		// AI销售金额
		BigDecimal monthOfSpecAiAmountOfOrder = statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(2, null, 1l, startDate, endDate,null);
		excelMonthlyDistributeOrderData.setMonthOfSpecAiAmountOfOrder(monthOfSpecAiAmountOfOrder);
		//设备销售金额
		BigDecimal monthOfSpecEqAmountOfOrder = statisticsExportMapper.getMonthGoodsTypeAmountOfOrderByType(2, 2, null, startDate, endDate,null);
		excelMonthlyDistributeOrderData.setMonthOfSpecEqAmountOfOrder(monthOfSpecEqAmountOfOrder);

		//分销提现数据
		BigDecimal shouldApplyMonty = statisticsExportMapper.getShouldApplyMoney(endDate);
		excelMonthlyDistributeOrderData.setShouldApplyMoney(shouldApplyMonty);
		BigDecimal realApplyMoney = statisticsExportMapper.getRealApplyMoney(endDate);
		excelMonthlyDistributeOrderData.setRealApplyMoney(realApplyMoney);

		//分销转账数据
		Map<String, BigDecimal> transferDataMap = statisticsExportMapper.getTransferData(startDate, endDate);
		BigDecimal autoMoney = Optional.ofNullable(transferDataMap.get("autoMoney")).orElse(BigDecimal.ZERO).divide(BigDecimal.valueOf(100));
		BigDecimal usdtMoney = Optional.ofNullable(transferDataMap.get("usdtMoney")).orElse(BigDecimal.ZERO).divide(BigDecimal.valueOf(100));
		BigDecimal manualMoney = Optional.ofNullable(transferDataMap.get("manualMoney")).orElse(BigDecimal.ZERO).divide(BigDecimal.valueOf(100));
		excelMonthlyDistributeOrderData.setAutoMoney(autoMoney);
		excelMonthlyDistributeOrderData.setUsdtMoney(usdtMoney);
		excelMonthlyDistributeOrderData.setManualMoney(manualMoney);

		//下单率
		//自然渠道用户数
		Integer natureUserSourceNum = statisticsExportMapper.getMonthUserSourceNumByType(1, startDate, endDate);
		//自然渠道下单人数
		Integer natureUserSourceOrderNum = statisticsExportMapper.getMonthUserSourceNumOrderByType(1, startDate, endDate);
		String natureUserSourceOrderRate;
		if (natureUserSourceNum == 0) {
			natureUserSourceOrderRate = StrUtil.EMPTY;
		} else {
			natureUserSourceOrderRate = BigDecimal.valueOf(natureUserSourceOrderNum).divide(BigDecimal.valueOf(natureUserSourceNum), 2, RoundingMode.HALF_DOWN).multiply(BigDecimal.valueOf(100)) + "%";
		}
		//分销渠道用户数
		Integer channelUserSourceNum = statisticsExportMapper.getMonthUserSourceNumByType(2, startDate, endDate);
		Integer channelUserSourceOrderNum = statisticsExportMapper.getMonthUserSourceNumOrderByType(2, startDate, endDate);
		String channelUserSourceOrderRate = BigDecimal.valueOf(channelUserSourceOrderNum).divide(BigDecimal.valueOf(channelUserSourceNum), 2, RoundingMode.HALF_DOWN).multiply(BigDecimal.valueOf(100)) + "%";

		excelMonthlyDistributeOrderData.setNatureUserSourceNum(natureUserSourceNum);
		excelMonthlyDistributeOrderData.setNatureUserSourceOrderNum(natureUserSourceOrderNum);
		excelMonthlyDistributeOrderData.setNatureUserSourceOrderRate(natureUserSourceOrderRate);

		excelMonthlyDistributeOrderData.setChannelUserSourceNum(channelUserSourceNum);
		excelMonthlyDistributeOrderData.setChannelUserSourceOrderNum(channelUserSourceOrderNum);
		excelMonthlyDistributeOrderData.setChannelUserSourceOrderRate(channelUserSourceOrderRate);

		Map<String, Long> epOrderSourceMap = statisticsExportMapper.getEpOrderNumsGroupSource(startDate, endDate);

		Integer naturalEpOrders = Integer.parseInt(epOrderSourceMap.get("naturalEpOrders").toString());
		Integer distributeOrders = Integer.parseInt(epOrderSourceMap.get("distributeOrders").toString());
		excelMonthlyDistributeOrderData.setNatureUserSourceEpOrderNum(naturalEpOrders);
		excelMonthlyDistributeOrderData.setChannelUserSourceEpOrderNum(distributeOrders);
		excelSheetDataList.add(new ExcelSheetAndData("每月用户分销数据", List.of(excelMonthlyDistributeOrderData), ExcelMonthlyDistributeOrderData.class, 2));
	}

	private void exportRegisterData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
		List<ExcelRegisterAccountData> registerAccountData = new ArrayList<>();
		Constant.registerAccount.forEach(platform -> {
			List<RegisterOrderDon> registerOrderDons = statisticsUserDataMapper.getPlatformHasPaymentOrders(platform, startDate, endDate);
			if (registerOrderDons.isEmpty()) {
				return;
			}
			ExcelRegisterAccountData registerDataExcel = new ExcelRegisterAccountData();
			registerDataExcel.setPlatform(platform);
			registerDataExcel.setNumOfOrder(registerOrderDons.size());
			Set<Long> userSet = registerOrderDons.stream().map(RegisterOrderDon::getUserId).collect(Collectors.toSet());
			registerDataExcel.setNumOfUser(userSet.size());
			Optional<BigDecimal> reduce = registerOrderDons.stream().map(RegisterOrderDon::getMoney).reduce(BigDecimal::add);
			registerDataExcel.setMoney(reduce.isPresent() ? reduce.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO);
			registerAccountData.add(registerDataExcel);
		});
		if (registerAccountData.isEmpty()) {
			return;
		}
		excelSheetDataList.add(new ExcelSheetAndData("注册账号数据", registerAccountData, ExcelRegisterAccountData.class, 7));
	}

	private void exportFashionData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
		List<GoodsDonSkuView> goodsDonSkuViews = goodsDonMapper.selectGoodsDonSkuByGoodsType(Constant.realGoodsType.get(1));
		List<ExcelRealGoodsData> fashionData = new ArrayList<>();
		goodsDonSkuViews.forEach(goodsDonSkuView -> {
			Long skuId = goodsDonSkuView.getSkuId();
			String goodsTitle = goodsDonSkuView.getGoodsTitle();
			String specVal = goodsDonSkuView.getSpecVal();
			//订单数据
			ExcelRealGoodsData exportData = statisticsUserDataMapper.getExportGoodsDonDataBySkuId(skuId, startDate, endDate);
			if (exportData == null || exportData.getNumOfOrder() == 0) {
				return;
			}
			exportData.setName(goodsTitle);
			exportData.setSpecVal(specVal);

			fashionData.add(exportData);
		});
		if (fashionData.isEmpty()) {
			return;
		}
		excelSheetDataList.add(new ExcelSheetAndData("潮玩好物", fashionData, ExcelRealGoodsData.class, 6));
	}

	private void exportRealGoodsData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
		List<GoodsDonSkuView> goodsDonSkuViews = goodsDonMapper.selectGoodsDonSkuByGoodsType(Constant.realGoodsType.get(0));
		List<ExcelRealGoodsData> realGoodsData = new ArrayList<>();
		goodsDonSkuViews.forEach(goodsDonSkuView -> {
			Long skuId = goodsDonSkuView.getSkuId();
			String goodsTitle = goodsDonSkuView.getGoodsTitle();
			String specVal = goodsDonSkuView.getSpecVal();
			//订单数据
			ExcelRealGoodsData exportData = statisticsUserDataMapper.getExportGoodsDonDataBySkuId(skuId, startDate, endDate);
			if (exportData == null || exportData.getNumOfOrder() == 0) {
				return;
			}
			exportData.setName(goodsTitle);
			exportData.setSpecVal(specVal);

			realGoodsData.add(exportData);
		});
		if (realGoodsData.isEmpty()) {
			return;
		}
		excelSheetDataList.add(new ExcelSheetAndData("硬件设备数据", realGoodsData, ExcelRealGoodsData.class, 5));
	}

	private void exportStreamingAccountData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
		Long appleOneGoodsId = 2l;
		List<GoodsDon> goodsDons = goodsDonMapper.selectList(Wrappers.lambdaQuery(GoodsDon.class)
				.ne(GoodsDon::getId, appleOneGoodsId)
				.eq(GoodsDon::getType, 1)
				.eq(GoodsDon::getDeleted, 1));
		List<ExcelStreamingAccountData> streamingAccountData = new ArrayList<>();
		goodsDons.forEach((goods) -> {
			Long goodsId = goods.getId();
			//订单数据
			ExcelStreamingAccountData exportData = statisticsUserDataMapper.getExportStreamingAccountData(goodsId, null, null, startDate, endDate);
			if (exportData == null || exportData.getNumOfUser() == 0) {
				return;
			}
			exportData.setName(goods.getTitle());
			//月、季、年
			exportData.setMonth(statisticsUserDataMapper.getTypeData(goodsId, Constant.payType.get(0), startDate, endDate));
			exportData.setSeason(statisticsUserDataMapper.getTypeData(goodsId, Constant.payType.get(1), startDate, endDate));
			exportData.setYear(statisticsUserDataMapper.getTypeData(goodsId, Constant.payType.get(2), startDate, endDate));
			streamingAccountData.add(exportData);
		});
		if (streamingAccountData.isEmpty()) {
			return;
		}
		excelSheetDataList.add(new ExcelSheetAndData("流媒体账号数据", streamingAccountData, ExcelStreamingAccountData.class, 4));
	}

	private void exportAppleOneData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
		Map<String, List<GoodsDonSku>> appleOneMap = statistics.getAppleOneMap();
		List<ExcelAppleOneData> appleData = new ArrayList<>();
		appleOneMap.forEach((areaName, goodsDonSkuList) -> {
			Set<Long> skuIds = goodsDonSkuList.stream().map(GoodsDonSku::getId).collect(Collectors.toSet());
			ExcelAppleOneData appleDataExcel = statisticsExportMapper.getAppleOneDataThisMonth(skuIds, startDate, endDate);
			if (appleDataExcel == null || appleDataExcel.getNumOfOrder() == 0) {
				return;
			}
			appleDataExcel.setArea(areaName);

			Integer monthOrder = 0;
			Integer searOrder = 0;
			Integer yearOrder = 0;
			for (GoodsDonSku sku : goodsDonSkuList) {
				Long skuId = sku.getId();
				if (StrUtil.isNotBlank(sku.getSpecVal())) {
					if (sku.getSpecVal().contains(Constant.payType.get(0)) && !sku.getSpecVal().contains(Constant.payType.get(2))) {
						monthOrder += statisticsExportMapper.getAppleOnePayMonthTypeOrderThisMonth(skuId, startDate, endDate);
					} else if (sku.getSpecVal().contains(Constant.payType.get(1))) {
						searOrder += statisticsExportMapper.getAppleOnePayMonthTypeOrderThisMonth(skuId, startDate, endDate);
					} else if (!sku.getSpecVal().contains(Constant.payType.get(0)) && sku.getSpecVal().contains(Constant.payType.get(2))) {
						yearOrder += statisticsExportMapper.getAppleOnePayMonthTypeOrderThisMonth(skuId, startDate, endDate);
					}
				}
			}
			appleDataExcel.setMonth(monthOrder);
			appleDataExcel.setSeason(searOrder);
			appleDataExcel.setYear(yearOrder);
			appleData.add(appleDataExcel);
		});
		if (appleData.isEmpty()) {
			return;
		}
		excelSheetDataList.add(new ExcelSheetAndData("Apple One数据", appleData, ExcelAppleOneData.class, 3));
	}


	private void getAppleOneDataView(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && (DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate) || DateUtil.endOfDay(DateTime.now()).equals(endDate))) {
			List<AppleOneData> appleOneData1 = statistics.statisticsAppleOneData(startDate, endDate, true);
			List<AppleOneData> collect = appleOneData1.stream().filter(data -> {
				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
					data.setMoney(data.getMoney().divide(BigDecimal.valueOf(100)));
					data.setRefundMoney(getAppleOneRefundMoneyByArea(data.getAreaName(), startDate, endDate));
					data.setDistributeOrderMoney(data.getDistributeOrderMoney().divide(BigDecimal.valueOf(100)));
					return true;
				}
				return false;
			}).collect(Collectors.toList());
			backgroundDataView.setAppleOneDataViews(collect);
		} else {
			List<AppleOneData> appleOneData = appleOneDataMapper.statisticsAppleOneData(startDate, endDate);
			appleOneData.forEach(data -> {
				data.setRefundMoney(getAppleOneRefundMoneyByArea(data.getAreaName(), startDate, endDate));
			});
			backgroundDataView.setAppleOneDataViews(appleOneData);
		}
	}

	private void getStreamingAccountDataView(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
		//当天
		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && (DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate) || DateUtil.endOfDay(DateTime.now()).equals(endDate))) {
			List<StreamingAccountData> streamingAccountData = statistics.statisticsStreamingAccountData(startDate, endDate, true);
			List<StreamingAccountData> collect = streamingAccountData.stream().filter(data -> {
				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
					data.setRefundMoney(getRefundMoney(data.getGoodsId(), null, startDate, endDate));
					data.setMoney(data.getMoney().divide(BigDecimal.valueOf(100)));
					return true;
				}
				return false;
			}).collect(Collectors.toList());
			backgroundDataView.setStreamAccountDataViews(collect);
		} else {
			List<StreamingAccountData> streamingAccountData = streamingAccountDataMapper.statisticsStreamingData(startDate, endDate);
			Optional.ofNullable(streamingAccountData).ifPresent(list -> list.forEach(data -> {
				GoodsDon goodsDon = goodsDonMapper.selectOne(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getId, data.getGoodsId()).last("limit 1"));
				if (goodsDon != null) {
					data.setAccountName(goodsDon.getTitle());
				}
				data.setRefundMoney(getRefundMoney(data.getGoodsId(), null, startDate, endDate));
			}));
			backgroundDataView.setStreamAccountDataViews(streamingAccountData);
		}
	}

	private void getRealGoodsData(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && (DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate) || DateUtil.endOfDay(DateTime.now()).equals(endDate))) {
			List<RealGoodsData> realGoodsData = statistics.statisticsRealGoodsData(startDate, endDate, true);
			List<RealGoodsData> collect = realGoodsData.stream().filter(data -> {
				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
					data.setRefundMoney(getRefundMoney(null, data.getSkuId(), startDate, endDate));
					data.setNumOfRefundOrder(getNumOfRefundOrder(null, data.getSkuId(), startDate, endDate));
					data.setMoney(data.getMoney().divide(BigDecimal.valueOf(100)));
					return true;
				}
				return false;
			}).collect(Collectors.toList());
			backgroundDataView.setRealGoodsDataViews(collect);
		} else {
			List<RealGoodsData> realGoodsData = realGoodsDataMapper.statisticsRealGoodsData(startDate, endDate);
			Optional.ofNullable(realGoodsData).ifPresent(list -> list.forEach(data -> {
				GoodsDonSkuView goodsDonSkuView = beanSearcher.searchFirst(GoodsDonSkuView.class, MapUtils.builder().field(GoodsDonSkuView::getSkuId, data.getSkuId()).build());
				if (goodsDonSkuView != null) {
					data.setGoodsTitle(goodsDonSkuView.getGoodsTitle());
					data.setSpecVal(goodsDonSkuView.getSpecVal());
				}
				data.setRefundMoney(getRefundMoney(null, data.getSkuId(), startDate, endDate));
				data.setNumOfRefundOrder(getNumOfRefundOrder(null, data.getSkuId(), startDate, endDate));
			}));
			backgroundDataView.setRealGoodsDataViews(realGoodsData);
		}
	}

	private BackgroundDataView getHeaderData(Date startDate, Date endDate) {
		BackgroundDataView backgroundDataView = orderDonMapper.getBackgroundDataView(startDate, endDate, Constant.noOrderStatus);
		if (startDate != null || endDate != null) {
			BigDecimal totalRefundMoney = orderDonMapper.getTotalRefundAmountTime(startDate, endDate);
			backgroundDataView.setTotalRefundAmount(totalRefundMoney);
		}
		//近5天将要到期的主账号总数
		DateTime now = DateTime.now();
		DateTime zero = DateUtil.beginOfDay(now);
		DateTime fiveDays = DateUtil.offsetDay(zero, 5);
		//5天后将到期的主账号
		Integer willExpireAccounts = accountService.count(Wrappers.lambdaQuery(Account.class).between(Account::getExpiryTime, zero, fiveDays));
		backgroundDataView.setTotalNumOfWillExpireAccount(willExpireAccounts);
		//已到期主账号
		Integer expiredAccounts = accountService.count(Wrappers.lambdaQuery(Account.class).le(Account::getExpiryTime, now));
		backgroundDataView.setTotalExpiredAccountNum(expiredAccounts);
		//虚物
		setGoodsMoneyAndOrder(1, startDate, endDate, backgroundDataView);
		//实物
		setGoodsMoneyAndOrder(2, startDate, endDate, backgroundDataView);
		//潮玩
		setGoodsMoneyAndOrder(3, startDate, endDate, backgroundDataView);
		//已使用余额
		BigDecimal usedBalance = orderDonMapper.statisticsUsedBalance(startDate, endDate, Constant.noOrderAllStatus);
		backgroundDataView.setUsedBalance(usedBalance);
		//剩余余额
		BigDecimal remainBalance = userMapper.statisticsRemainBalance();
		backgroundDataView.setRemainBalance(remainBalance);
		return backgroundDataView;
	}

	/**
	 * 分销金额信息补充
	 *
	 * @param backgroundDataView
	 */
	@Override
	public void distribute(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
		List<DistributeOrdersView> distributeOrders = Optional.ofNullable(beanSearcher.searchAll(DistributeOrdersView.class, MapUtils.builder()
				.field(DistributeOrdersView::getCreatedTime, startDate, endDate).op(Operator.Between)
				.build())).orElse(new ArrayList<>());
		backgroundDataView.setDistributeOrders(distributeOrders.size());
		//固定推广者订单
		List<DistributeOrdersView> distributePopularizeOrders = Optional.ofNullable(beanSearcher.searchAll(DistributeOrdersView.class, MapUtils.builder()
				.put("f", " and ifnull(od.is_fixed_distribute,vod.is_fixed_distribute) = 1")
				.field(DistributeOrdersView::getCreatedTime, startDate, endDate).op(Operator.Between)
				.build())).orElse(new ArrayList<>());
		backgroundDataView.setDistributePopularizeOrders(distributePopularizeOrders.size());
		//普通分销单数
		List<DistributeOrdersView> distributeOriginalOrders = Optional.ofNullable(beanSearcher.searchAll(DistributeOrdersView.class, MapUtils.builder()
				.put("f", " and ifnull(od.is_fixed_distribute,vod.is_fixed_distribute) = 0")
				.field(DistributeOrdersView::getCreatedTime, startDate, endDate).op(Operator.Between)
				.build())).orElse(new ArrayList<>());
		backgroundDataView.setDistributeOriginalOrders(distributeOriginalOrders.size());
		//固定推广者订单金额
		Optional<BigDecimal> popularizeMoney = distributePopularizeOrders.stream().map(DistributeOrdersView::getMoney).reduce(BigDecimal::add);
		//普通分销订单金额
		Optional<BigDecimal> originalMoney = distributeOriginalOrders.stream().map(DistributeOrdersView::getMoney).reduce(BigDecimal::add);
		backgroundDataView.setDistributePopularizeMoney(popularizeMoney.isPresent() ? popularizeMoney.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO);
		backgroundDataView.setDistributeOriginalMoney(originalMoney.isPresent() ? originalMoney.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO);

		List<DistributeMoneyApply> distributeMoneyApplies = Optional.ofNullable(beanSearcher.searchAll(DistributeMoneyApply.class, MapUtils.builder().field(DistributeMoneyApply::getCreatedTime, startDate, endDate).op(Operator.Between).build())).orElse(new ArrayList<>());
		Map<DistributeMoneyApply.Status, List<DistributeMoneyApply>> collect = distributeMoneyApplies.stream().collect(Collectors.groupingBy(DistributeMoneyApply::getVerifyStatus));
		collect.forEach((k, v) -> {
			if (DistributeMoneyApply.Status.fail == k) {
				return;
			}
			Optional<BigDecimal> reduce = v.stream().map(DistributeMoneyApply::getMoney).reduce(BigDecimal::add);
			BigDecimal money = reduce.isPresent() ? reduce.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
			if (DistributeMoneyApply.Status.success == k) {
				backgroundDataView.setDistributeGotMoney(money);
			}
			if (DistributeMoneyApply.Status.verifying == k) {
				backgroundDataView.setDistributeVerifyingMoney(money);
			}
		});
		if (backgroundDataView.getDistributeGotMoney() == null) {
			backgroundDataView.setDistributeGotMoney(BigDecimal.ZERO);
		}

		if (backgroundDataView.getDistributeVerifyingMoney() == null) {
			backgroundDataView.setDistributeVerifyingMoney(BigDecimal.ZERO);
		}
	}

	public BigDecimal getRefundMoney(Long goodsId, Long skuId, Date startDate, Date endDate) {
		Number refundMoneyNumber = beanSearcher.searchSum(OrderDon.class, MapUtils.builder()
				.field(OrderDon::getGoodsId, goodsId)
				.field(OrderDon::getSkuId, skuId)
				.field(OrderDon::getStatus, OrderDon.Status.refund.name())
				.field(OrderDon::getCreatedTime, startDate, endDate).op(Operator.Between)
				.build(), "refundMoney");
		BigDecimal refundMoney = BigDecimal.valueOf(refundMoneyNumber.intValue()).divide(BigDecimal.valueOf(100));
		return refundMoney;
	}

	private Integer getNumOfRefundOrder(Long goodsId, Long skuId, Date startDate, Date endDate) {
		Number number = beanSearcher.searchCount(OrderDon.class, MapUtils.builder()
				.field(OrderDon::getGoodsId, goodsId)
				.field(OrderDon::getSkuId, skuId)
				.field(OrderDon::getStatus, OrderDon.Status.refund.name())
				.field(OrderDon::getCreatedTime, startDate, endDate).op(Operator.Between)
				.build());
		return number.intValue();
	}

	public void setGoodsMoneyAndOrder(Integer type, Date startDate, Date endDate, BackgroundDataView backgroundDataView) {
		Map<String, Object> map = orderDonMapper.getOrderDetailByGoodsType(type, Constant.noOrderStatus, startDate, endDate);
		Integer totalOrder = Integer.parseInt(map.get("orderNum").toString());
		BigDecimal orderMoney = BigDecimal.valueOf(Long.parseLong(map.get("money").toString())).divide(BigDecimal.valueOf(100));
		if (type == 1) {
			backgroundDataView.setVirtualNumOfOrder(totalOrder);
			backgroundDataView.setVirtualAccountOfOrder(orderMoney);
		} else if (type == 2) {
			backgroundDataView.setRealGoodsNumOfOrder(totalOrder);
			backgroundDataView.setRealGoodsAccountOfOrder(orderMoney);
		} else if (type == 3) {
			backgroundDataView.setFashionNumOfOrder(totalOrder);
			backgroundDataView.setFashionAccountOfOrder(orderMoney);
		}
	}

	private BigDecimal getAppleOneRefundMoneyByArea(String areaName, Date startDate, Date endDate) {
		Number refundMoneyNumber = beanSearcher.searchSum(OrderDonView.class, MapUtils.builder()
				.field(OrderDonView::getSpecVal, areaName).op(Operator.Contain)
				.field(OrderDon::getStatus, OrderDon.Status.refund.name())
				.field(OrderDon::getCreatedTime, startDate, endDate).op(Operator.Between)
				.build(), "refundMoney");
		BigDecimal refundMoney = BigDecimal.valueOf(refundMoneyNumber.intValue()).divide(BigDecimal.valueOf(100));
		return refundMoney;
	}
}
