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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
import com.cyksj.mapper.GoodsDonMapper;
import com.cyksj.mapper.RegisterAccountDataMapper;
import com.cyksj.mapper.RegisterOrderDonMapper;
import com.cyksj.mapper.corp.CorpUserAuthMapper;
import com.cyksj.mapper.manage.statistics.*;
import com.cyksj.model.entity.*;
import com.cyksj.model.views.CorpUserTagView;
import com.cyksj.model.views.StatisticsGoodsDataView;
import com.cyksj.service.mange.CmsAccountService;
import com.cyksj.service.mange.CmsGoodsDonSkuService;
import com.cyksj.service.mange.statistics.StatisticsDataDayService;
import com.cyksj.service.order.OrderDonService;
import com.ejlchina.searcher.BeanSearcher;
import com.ejlchina.searcher.util.MapBuilder;
import com.ejlchina.searcher.util.MapUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/*
 *项目名: netflix
 *文件名: StatisticsDataDayServiceImpl
 *创建者: JavaZou
 *创建时间:2023/7/6 13:40
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class StatisticsDataDayServiceImpl implements StatisticsDataDayService {
	private final OrderDonService orderDonService;

	private final CmsGoodsDonSkuService goodsDonSkuService;

	private final CmsAccountService accountService;

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

	private final AppleOneDataMapper appleOneDataMapper;

	private final StreamingAccountDataMapper streamingAccountDataMapper;

	private final GoodsDonMapper goodsDonMapper;

	private final RealGoodsDataMapper realGoodsDataMapper;

	private final RegisterOrderDonMapper registerOrderDonMapper;

	private final RegisterAccountDataMapper registerAccountDataMapper;

	private final StatisticsUserDataMapper statisticsUserDataMapper;

	private final StatisticsFashionGoodsDataMapper statisticsFashionGoodsDataMapper;

	private final BeanSearcher beanSearcher;

	private final CorpUserAuthMapper corpUserAuthMapper;

	public List<StatisticsFashionGoodsData> statisticsFashionGoodsData(Date yesZeroDate, Date thisZeroDate, Boolean today) {
		//潮玩好物
		List<GoodsDon> goodsDons = goodsDonMapper.selectList(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getType, Constant.realGoodsType.get(1)));
		List<StatisticsFashionGoodsData> fashionGoodsData = new ArrayList<>();
		goodsDons.forEach(goods -> {
			List<StatisticsGoodsDataView> goodsDataViews = beanSearcher.searchAll(StatisticsGoodsDataView.class, MapUtils.builder()
					.field(StatisticsGoodsDataView::getGoodsId, goods.getId())
					.put("time", String.format("od.created_time between '%s' and '%s'", yesZeroDate, thisZeroDate))
					.build());
			goodsDataViews.forEach(goodsDataView -> {
				StatisticsFashionGoodsData statisticsFashionGoodsData = new StatisticsFashionGoodsData();
				BeanUtil.copyProperties(goodsDataView, statisticsFashionGoodsData);
				fashionGoodsData.add(statisticsFashionGoodsData);
			});
		});
		if (today) {
			return fashionGoodsData;
		}
		if (!fashionGoodsData.isEmpty()) {
			fashionGoodsData.forEach(data -> {
				data.setStatisticsDate(yesZeroDate);
				statisticsFashionGoodsDataMapper.insert(data);
			});
		}
		return null;
	}

	/**
	 * 用户数据统计
	 */
	private void statisticsUserData(Date yesZeroDate, Date thisZeroDate) {
		StatisticsUserData yesData = statisticsUserDataMapper.selectOne(Wrappers.lambdaQuery(StatisticsUserData.class).orderByDesc(StatisticsUserData::getId)
				.lt(StatisticsUserData::getStatisticsDate, yesZeroDate)
				.select(StatisticsUserData::getNumOfUser, StatisticsUserData::getPcNumOfUser).last("limit 1"));
		Integer yesNumOfUser = yesData == null ? 0 : yesData.getNumOfUser();
		Integer yesPcNumOfUser = yesData == null ? 0 : yesData.getPcNumOfUser();
		StatisticsUserData statisticsUserData = Optional.ofNullable(statisticsUserDataMapper.selectOne(Wrappers.lambdaQuery(StatisticsUserData.class).eq(StatisticsUserData::getStatisticsDate, yesZeroDate).last("limit 1"))).orElse(new StatisticsUserData());
		statisticsUserData.setNumOfNewUser(statisticsUserDataMapper.getNumOfNewUser(yesZeroDate, thisZeroDate));
		statisticsUserData.setNumOfActiveUser(statisticsUserDataMapper.getNumOfActiveUser(yesZeroDate, thisZeroDate));
		statisticsUserData.setNumOfUser(yesNumOfUser + statisticsUserData.getNumOfNewUser());

		statisticsUserData.setNumOfDistributeUser(statisticsUserDataMapper.getNumOfDistributeUserToday(yesZeroDate, thisZeroDate));

		List<CorpUserAuth> corpUserAuths = corpUserAuthMapper.selectList(Wrappers.lambdaQuery(CorpUserAuth.class)
				.between(CorpUserAuth::getCreatedTime, yesZeroDate, thisZeroDate).select(CorpUserAuth::getExternalUserid).groupBy(CorpUserAuth::getExternalUserid));
		Integer numOfCorpUser = corpUserAuths.isEmpty() ? 0 : corpUserAuths.size();
		statisticsUserData.setNumOfCorpUser(numOfCorpUser);
		MapBuilder builder = MapUtils.builder()
				.put("time", String.format("cfr.created_time between '%s' and '%s'", yesZeroDate, thisZeroDate))
				.group("cfr.corp_user_id");
		Number equipments = beanSearcher.searchCount(CorpUserTagView.class, builder.put("tagName", "ct.tag_name = '设备'").build());
		statisticsUserData.setNumOfCorpEquipmentUser(equipments.intValue());
		Number accounts = beanSearcher.searchCount(CorpUserTagView.class, builder.put("tagName", "ct.tag_name = '账号'").build());
		statisticsUserData.setNumOfCorpAccountUser(accounts.intValue());

		statisticsUserData.setPcNumOfNewUser(statisticsUserDataMapper.getPcNumOfNewUser(yesZeroDate, thisZeroDate));
		statisticsUserData.setPcNumOfActiveUser(statisticsUserDataMapper.getPcNumOfActiveUser(yesZeroDate, thisZeroDate));
		statisticsUserData.setPcNumOfUser(yesPcNumOfUser + statisticsUserData.getPcNumOfNewUser());

		statisticsUserData.setStatisticsDate(yesZeroDate);
		if (statisticsUserData.getId() != null) {
			statisticsUserDataMapper.updateById(statisticsUserData);
			return;
		}
		statisticsUserDataMapper.insert(statisticsUserData);
	}

	/**
	 * 注册账号数据
	 */
	public List<RegisterAccountData> statisticsRegisterAccountData(Date yesZeroDate, Date thisZeroDate, Boolean today) {
		List<RegisterAccountData> list = new ArrayList<>();
		Constant.registerAccount.forEach(platform -> {
			RegisterAccountData entity = Optional.ofNullable(registerOrderDonMapper.registerAccountDataEveryDay(yesZeroDate, thisZeroDate, platform)).orElse(new RegisterAccountData());
			entity.setPlatform(platform);
			RegisterAccountData dto = Optional.ofNullable(registerOrderDonMapper.selectRefundOrderDetail(yesZeroDate, thisZeroDate, platform)).orElse(new RegisterAccountData());
			entity.setNumOfRefundOrder(dto.getNumOfRefundOrder());
			entity.setRefundMoney(dto.getRefundMoney());
			entity.setStatisticsDate(yesZeroDate);
			if (today) {
				list.add(entity);
				return;
			}
			registerAccountDataMapper.insert(entity);
		});
		if (today) {
			return list;
		}
		return null;
	}

	/**
	 * 统计AppleOne数据
	 *
	 * @return
	 */
	public List<AppleOneData> statisticsAppleOneData(Date yesZeroDate, Date thisZeroDate, Boolean today) {
		Map<String, List<GoodsDonSku>> areaDataMap = getAppleOneMap();

		List<AbstractBackData> appleOneSave = new ArrayList<>();
		List<AppleOneData> appleOneData = new ArrayList<>();
		areaDataMap.forEach((areaName, skus) -> {
			AppleOneData appleOne = new AppleOneData();
			appleOne.setAreaName(areaName);
			//通过skuIds找到对应的appleOne统计数据
			List<Long> skuIds = skus.stream().map(GoodsDonSku::getId).collect(Collectors.toList());
			List<OrderDon> orderDons = Optional.ofNullable(orderDonService.getAppleOneOrderDons(skuIds, Constant.noOrderStatus, yesZeroDate, thisZeroDate)).orElse(new ArrayList<>());
			appleOneDataStatistics(orderDons, appleOne, appleOneSave);
		});

		for (AbstractBackData appleOne : appleOneSave) {
			appleOne.setStatisticsDate(yesZeroDate);
			if (today) {
				appleOneData.add((AppleOneData) appleOne);
				continue;
			}
			appleOneDataMapper.insert((AppleOneData) appleOne);
		}
		if (today) {
			return appleOneData;
		}
		return null;
	}

	private void appleOneDataStatistics(List<OrderDon> orderDons, AppleOneData appleOne, List<AbstractBackData> appleOneSave) {
		if (CollUtil.isNotEmpty(orderDons)) {
			//用户人数
			Set<Long> numOfUser = Optional.ofNullable(orderDons.stream().map(OrderDon::getUserId).collect(Collectors.toSet())).orElse(new HashSet<>());
			appleOne.setNumOfUser(numOfUser.size());
			//订单数
			appleOne.setNumOfOrder(orderDons.size());
			//兑换码订单数
			List<OrderDon> exCodeOrders = Optional.ofNullable(orderDons.stream().filter(order -> order.getType() == OrderDon.Type.EX_CODE).collect(Collectors.toList())).orElse(new ArrayList<>());
			appleOne.setNumOfCodeOrder(exCodeOrders.size());
			//金额
			Optional<BigDecimal> money = orderDons.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
			if (money.isPresent()) {
				appleOne.setMoney(money.get());
			} else appleOne.setMoney(BigDecimal.ZERO);
			//分销订单
			List<OrderDon> distributeOrders = Optional.ofNullable(orderDons.stream().filter(ord -> ord.getIsDistribute()).collect(Collectors.toList())).orElse(new ArrayList<>());
			appleOne.setNumOfDistributeOrder(distributeOrders.size());
			Optional<BigDecimal> distributeMoney = distributeOrders.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
			appleOne.setDistributeOrderMoney(distributeMoney.isPresent() ? distributeMoney.get() : BigDecimal.ZERO);

			getNumOfOrderByPayType(orderDons, appleOne);
		}
		appleOneSave.add(appleOne);
	}

	/**
	 * 统计流媒体账号数据
	 */
	public List<StreamingAccountData> statisticsStreamingAccountData(Date yesZeroDate, Date thisZeroDate, Boolean today) {
		Long appleOndGoodsId = 2l;
		List<GoodsDon> goodsDons = goodsDonMapper.selectList(Wrappers.lambdaQuery(GoodsDon.class)
				.ne(GoodsDon::getId, appleOndGoodsId)
				.eq(GoodsDon::getType, 1)
				.eq(GoodsDon::getDeleted, 1));
		List<StreamingAccountData> streamingAccountDataSave = new ArrayList<>(goodsDons.size());
		goodsDons.forEach(goods->{
			StreamingAccountData streamingAccount = new StreamingAccountData();
			Long goodsId = goods.getId();
			streamingAccount.setAccountName(goods.getTitle());
			streamingAccount.setGoodsId(goodsId);
			streamingAccountDataStatistics(goodsId, streamingAccount, streamingAccountDataSave, yesZeroDate, thisZeroDate);
		});
		if (today) {
			return streamingAccountDataSave;
		}
		for (StreamingAccountData streamingAccountData : streamingAccountDataSave) {
			streamingAccountData.setStatisticsDate(yesZeroDate);
			streamingAccountDataMapper.insert(streamingAccountData);
		}
		return null;
	}

	/**
	 * 统计实物数据
	 */
	public List<RealGoodsData> statisticsRealGoodsData(Date yesZeroDate, Date thisZeroDate, Boolean today) {
		List<GoodsDon> goodsDons = goodsDonMapper.selectList(Wrappers.lambdaQuery(GoodsDon.class)
				.eq(GoodsDon::getType, Constant.realGoodsType.get(0))
				.eq(GoodsDon::getDeleted, 1));
		List<RealGoodsData> realGoodsDataList = new ArrayList<>();
		if (!goodsDons.isEmpty()) {
			goodsDons.forEach(goods -> {
				List<GoodsDonSku> skuList = goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, goods.getId()));
				if (!skuList.isEmpty()) {
					skuList.forEach(sku -> {
						RealGoodsData realGoodsData = new RealGoodsData();
						realGoodsData.setGoodsId(goods.getId());
						realGoodsData.setGoodsTitle(goods.getTitle());
						realGoodsData.setSkuId(sku.getId());
						realGoodsData.setSpecVal(sku.getSpecVal());
						//订单
						List<OrderDon> orderDon = Optional.ofNullable(orderDonService.list(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getSkuId, sku.getId()).between(OrderDon::getCreatedTime, yesZeroDate, thisZeroDate).notIn(OrderDon::getStatus, Constant.noOrderStatus).select(OrderDon::getUserId, OrderDon::getMoney, OrderDon::getId))).orElse(new ArrayList<>());
						Set<Long> userList = Optional.ofNullable(orderDon.stream().map(OrderDon::getUserId).collect(Collectors.toSet())).orElse(new HashSet<>());
						//用户数
						realGoodsData.setNumOfUser(userList.size());
						//订单数
						realGoodsData.setNumOfOrder(orderDon.size());
						//金额
						Optional<BigDecimal> money = orderDon.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
						realGoodsData.setMoney(money.isPresent() ? money.get() : BigDecimal.ZERO);
						realGoodsDataList.add(realGoodsData);
					});
				}
			});
		}
		if (today) {
			return realGoodsDataList;
		}
		if (!realGoodsDataList.isEmpty()) {
			realGoodsDataList.forEach(data -> {
				data.setStatisticsDate(yesZeroDate);
				realGoodsDataMapper.insert(data);
			});
		}
		return null;
	}

	/**
	 * @param goodsId              平台id
	 * @param streamingAccountData
	 * @param dataSave             入库实体集合
	 * @param yesZeroDate          昨日零时
	 * @param thisZeroDate         今日零时
	 */
	private void streamingAccountDataStatistics(Long goodsId, StreamingAccountData streamingAccountData, List<StreamingAccountData> dataSave, Date yesZeroDate, Date thisZeroDate) {
		//规格
		List<GoodsDonSku> list = Optional.ofNullable(goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, goodsId).select(GoodsDonSku::getId))).orElse(new ArrayList<>());
		List<Long> skuIds = list.stream().map(GoodsDonSku::getId).collect(Collectors.toList());
		if (CollUtil.isNotEmpty(skuIds)) {
			List<OrderDon> orderDons = Optional.ofNullable(accountService.getNoAppleOneOrderDon(skuIds, yesZeroDate, thisZeroDate, Constant.noOrderStatus)).orElse(new ArrayList<>());
			//用户数
			streamingAccountData.setNumOfUser(orderDons.stream().map(OrderDon::getUserId).collect(Collectors.toSet()).size());
			getNumOfOrderByPayType(orderDons, streamingAccountData);
			//兑换码订单数
			List<OrderDon> exCodeOrders = Optional.ofNullable(orderDons.stream().filter(order -> order.getType() == OrderDon.Type.EX_CODE).collect(Collectors.toList())).orElse(new ArrayList<>());
			streamingAccountData.setNumOfCodeOrder(exCodeOrders.size());
			streamingAccountData.setNumOfOrder(orderDons.size());
			Optional<BigDecimal> reduce = orderDons.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
			BigDecimal totalMoney = BigDecimal.valueOf(0);
			if (reduce.isPresent()) {
				totalMoney = reduce.get();
			}
			//金额
			streamingAccountData.setMoney(totalMoney);
			//分销订单
			List<OrderDon> distributeOrders = Optional.ofNullable(orderDons.stream().filter(ord -> ord.getIsDistribute()).collect(Collectors.toList())).orElse(new ArrayList<>());
			streamingAccountData.setNumOfDistributeOrder(distributeOrders.size());
			Optional<BigDecimal> distributeMoney = distributeOrders.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
			streamingAccountData.setDistributeOrderMoney(distributeMoney.isPresent() ? distributeMoney.get() : BigDecimal.ZERO);
		}
		dataSave.add(streamingAccountData);
	}

	/**
	 * 根据不同支付条件统计对应月、季、年订单
	 */
	private void getNumOfOrderByPayType(List<OrderDon> orderDons, AbstractBackData backData) {
		Integer numOfMonthOrder = 0;
		Integer numOfSeasonOrder = 0;
		Integer numOfYearOrder = 0;
		Map<Long, List<OrderDon>> skuIdMaps = Optional.ofNullable(orderDons.stream().collect(Collectors.groupingBy(OrderDon::getSkuId))).orElse(new HashMap<>());
		if (!skuIdMaps.isEmpty()) {
			List<GoodsDonSku> goodsDonSkus = Optional.ofNullable(goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).in(GoodsDonSku::getId, skuIdMaps.keySet()))).orElse(new ArrayList<>());
			for (GoodsDonSku donSkus : goodsDonSkus) {
				int size = skuIdMaps.get(donSkus.getId()).size();
				if (donSkus.getSpecVal().contains(Constant.payType.get(0)) && !donSkus.getSpecVal().contains(Constant.payType.get(2))) {
					numOfMonthOrder += size;
				} else if (donSkus.getSpecVal().contains(Constant.payType.get(1))) {
					numOfSeasonOrder += size;
				} else if (donSkus.getSpecVal().contains(Constant.payType.get(2))) {
					numOfYearOrder += size;
				}
			}
		}
		//月付
		backData.setNumOfMonthOrder(numOfMonthOrder);
		//季付
		backData.setNumOfSeasonOrder(numOfSeasonOrder);
		//年付
		backData.setNumOfYearOrder(numOfYearOrder);
	}

	/**
	 * 获取Apple区域map
	 */
	public Map<String, List<GoodsDonSku>> getAppleOneMap() {
		GoodsDon goodsDon = goodsDonMapper.selectOne(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getId, 2).last("limit 1"));
		List<GoodsDonSku> list = goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, goodsDon.getId()).select(GoodsDonSku::getId, GoodsDonSku::getSpecVal));
		Set<String> area = new HashSet<>();
		list.forEach(sku -> {
			String areaName = sku.getSpecVal().substring(0, sku.getSpecVal().indexOf("区") + 1);
			if (!area.contains(areaName)) {
				area.add(areaName);
			}
		});
		Map<String, List<GoodsDonSku>> areaDataMap = new HashMap<>();
		for (String name : area) {
			List<GoodsDonSku> sku = Optional.ofNullable(goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, 2).like(GoodsDonSku::getSpecVal, name).select(GoodsDonSku::getId, GoodsDonSku::getGoodsId, GoodsDonSku::getSpecVal))).orElse(new ArrayList<>());
			areaDataMap.put(name, sku);
		}
		return areaDataMap;
	}

}
