package com.qunzhixinxi.hnqz.daemon.quartz.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.qunzhixinxi.hnqz.admin.api.constant.CacheConstants;
import com.qunzhixinxi.hnqz.daemon.quartz.config.QuartzAppConfig;
import com.qunzhixinxi.hnqz.daemon.quartz.entity.*;
import com.qunzhixinxi.hnqz.daemon.quartz.enums.SubjectTypeEnum;
import com.qunzhixinxi.hnqz.daemon.quartz.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * {@code WmStatisticsServiceImpl} 类
 *
 * @author Hengchen.Sun
 * @version 1.0.0
 * @date 2021-06-07
 * @since ver.1.0.0
 */
@Service
@Slf4j
@AllArgsConstructor
public class WmStatisticsServiceImpl implements WmStatisticsService {

	private final QuartzAppConfig quartzAppConfig;
	private final WmScorePackageService wmScorePackageService;
	private final WmTaskSettleNoteService wmTaskSettleNoteService;
	private final WmScorePackageSettleNoteService wmScorePackageSettleNoteService;
	private final WmSettleAccountReceiveService wmSettleAccountReceiveService;
	private final WmDeptGmvService wmDeptGmvService;
	private final WmDeptGmvRecordService wmDeptGmvRecordService;
	private final SysDeptService sysDeptService;
	private final RedisTemplate redisTemplate;

	//需要忽略的部门
	private final List<String> ignoredDeptNameList = new ArrayList<>();

	{
		ignoredDeptNameList.add("要易业务管理平台");
		ignoredDeptNameList.add("小程序提审试用账号部门(勿删)");
		ignoredDeptNameList.add("小程序提审");
		ignoredDeptNameList.add("小程序提审2");
		ignoredDeptNameList.add("测试二代A");
//		ignoredDeptNameList.add("南疆区域");
//		ignoredDeptNameList.add("乌市区域");
//		ignoredDeptNameList.add("北疆区域");
//		ignoredDeptNameList.add("精细化招商");
		ignoredDeptNameList.add("测试CRO");
		ignoredDeptNameList.add("测试药企");
		ignoredDeptNameList.add("测试一级代理商");
		ignoredDeptNameList.add("测试-二级CSO");
		ignoredDeptNameList.add("测试二级代理商");
		ignoredDeptNameList.add("测试导出权限");
	}

	// 历史数据进行统一归类（如北疆区域、南疆区域、乌市区域都归类到新疆天山莲药业有限公司）
	private final Map<String, List<String>> convertMap = new HashMap<>();

	{
		// 新疆天山莲药业有限公司
		List<String> subList1 = new ArrayList<String>(){{
			add("北疆区域");
			add("南疆区域");
			add("乌市区域");
		}};
		convertMap.put("新疆天山莲药业有限公司", subList1);
		// 成都普什制药有限公司
		List<String> subList2 = new ArrayList<String>(){{
			add("精细化招商-安徽01");
			add("精细化招商-青海01");
			add("精细化招商-重庆01");
			add("精细化招商-山西02");
			add("精细化招商-山西01");
			add("精细化招商-广西02");
			add("精细化招商-陕西05");
			add("精细化招商-陕西04");
			add("精细化招商-陕西03");
			add("精细化招商-江苏01");
			add("精细化招商-河南01");
			add("精细化招商-内蒙古01");
			add("精细化招商-黑龙江01");
			add("精细化招商-辽宁02");
			add("精细化招商-辽宁01");
			add("精细化招商-湖北01");
			add("精细化招商-陕西02");
			add("精细化招商-陕西01");
			add("精细化招商-广西01");
			add("精细化招商-广东01");
			add("精细化招商-山东02");
			add("精细化招商-山东01");
			add("精细化招商-海南02");
			add("精细化招商-海南01");
			add("精细化招商（广西）");
			add("精细化招商-上海01");
		}};
		convertMap.put("成都普什制药有限公司", subList2);
	}

	// 账户充值的部门列表
	private final List<String> accountRechargeDeptNameList = new ArrayList<>();

	{
		accountRechargeDeptNameList.add("太原市曙光药业有限公司（本部）");
	}

	/**
	 * 每日统计GMVs
	 *
	 * @param params 参数 1-统计所有，2-统计当月
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void dailyGMVsStatistics(String params) {
		try {
			// 加锁
			Boolean absent = redisTemplate.opsForValue().setIfAbsent(CacheConstants.QUARTZ_DAILY_GMVS_STATISTICS + params, "1", 3600L, TimeUnit.SECONDS);
			if (!absent) {
				log.warn("dailyGMVsStatistics已经在执行了");
				return;
			}
			LocalDate today = LocalDate.now();
			if (StringUtils.isNotEmpty(params)) {
				if ("1".equals(params)) {
					// 一次性跑完从2020-06-07至今的每月数据
					LocalDate est = LocalDate.of(2020, 5, 20);
					while (est.isBefore(today)) {
						this.singleGMVsStatistics(est);
						est = est.plusDays(1);
					}
					// 历史数据处理
					this.processSpecialGMVData();
				} else if ("2".equals(params)) {
					// 统计当月
					this.singleGMVsStatistics(today);
				}
			}
		} catch (Exception e) {
			log.error("每日统计GMVs出错了", e);
		} finally {
			try {
				redisTemplate.delete(CacheConstants.QUARTZ_DAILY_GMVS_STATISTICS + params);
			} catch (Exception e) {
				log.error("每日统计GMVs出错了", e);
			}
		}
	}

	/**
	 * 统计当月GMV
	 * @param today
	 */
	private void singleGMVsStatistics(LocalDate today) {
		log.info("统计日期：{}", today.toString());
		// 获取要统计的部门
		List<SysDept> deptList = sysDeptService.listAllDept();
		// 过滤测试数据的部门
		List<SysDept> target = deptList.stream()
				.filter(dept -> !ignoredDeptNameList.contains(dept.getName()))
				.collect(Collectors.toList());

		// 如果是当前时间是每月的第一天，开始时间为上个月的的第一天
		LocalDate firstOfMonth = today.isEqual(today.withDayOfMonth(1)) ? today.minusMonths(1) : today.withDayOfMonth(1);
		// 获取统计的开始终止时间
		LocalDateTime start = firstOfMonth.atStartOfDay();
		LocalDateTime end = today.atStartOfDay().minusSeconds(1);

		BigDecimal scale = new BigDecimal("100");

		// 基于结算表，统计GMV1和GMV2
		List<WmDeptGMVs> deptGMVsList = new ArrayList<>();
		target.forEach(sysDept -> {
			// 统计GMV1
			List<WmScorePackage> scorePackageList = wmScorePackageService.list(Wrappers.<WmScorePackage>query()
					.eq("dept_id", sysDept.getDeptId())
					.eq("del_flag", "0")
					.eq("enable_flag", "0")
					.eq("package_finish_status", "1")
					.between("package_finish_time", start, end));
			final long userScoreSum = scorePackageList.stream()
					.filter(scorePackage -> StringUtils.isNumeric(scorePackage.getScore()))
					.mapToLong(scorePackage -> Long.parseLong(scorePackage.getScore()))
					.sum();

			// 统计GMV2：基于结算额
			long settleNoteSum = 0L;
			int renlijiaServiceChargeRate = sysDept.getRenlijiaServiceChargeRate() == null ? 0 : sysDept.getRenlijiaServiceChargeRate();
			if (!accountRechargeDeptNameList.contains(sysDept.getName())) {
				// 人力家
				List<WmScorePackageSettleNote> rljScorePackageSettleNoteList =
						wmScorePackageSettleNoteService.listSettleAmountByDeptId(sysDept.getDeptId(), SubjectTypeEnum.TYPE_RENLIJIA.getCode(), start, end);
				if (CollectionUtil.isNotEmpty(rljScorePackageSettleNoteList)) {
					long sum = rljScorePackageSettleNoteList.stream()
							.mapToLong(scorePackageSettleNote -> scorePackageSettleNote.getSettleAmount().multiply(scale).longValue())
							.sum();
					// 人力家实际结算额=结算额/(1+服务费率)
					settleNoteSum += Math.round(sum / (1 + renlijiaServiceChargeRate / 10000.0));
				}
				// 税邦云
				List<WmScorePackageSettleNote> sbyScorePackageSettleNoteList =
						wmScorePackageSettleNoteService.listSettleAmountByDeptId(sysDept.getDeptId(), SubjectTypeEnum.TYPE_SHUIBANGYUN.getCode(), start, end);
				if (CollectionUtil.isNotEmpty(sbyScorePackageSettleNoteList)) {
					long sum = sbyScorePackageSettleNoteList.stream()
							.mapToLong(scorePackageSettleNote -> scorePackageSettleNote.getSettleAmount().multiply(scale).longValue())
							.sum();
					settleNoteSum += sum;
				}
			} else {
				// 统计GMV2：基于充值表（目前只有太原曙光）
				LambdaQueryWrapper<WmSettleAccountReceive> queryWrapper = Wrappers.<WmSettleAccountReceive>lambdaQuery()
						.eq(WmSettleAccountReceive::getAccountName, sysDept.getName().replace("（本部）", ""))
						.between(WmSettleAccountReceive::getUpdateTime, start, end);
				List<WmSettleAccountReceive> accountReceiveList = wmSettleAccountReceiveService.list(queryWrapper);
				if (CollectionUtil.isNotEmpty(accountReceiveList)) {
					long sum = accountReceiveList.stream()
							.mapToLong(accountReceive -> new BigDecimal(accountReceive.getAmount()).multiply(scale).longValue())
							.sum();
					// 除以服务费的结果
					settleNoteSum = Math.round(sum / (1 + renlijiaServiceChargeRate / 10000.0));
				}
			}

			// 当日增量统计结果
			int gmv1Rate = sysDept.getGmv1Rate() == null ? 0 : sysDept.getGmv1Rate();
			int gmv2Rate = sysDept.getGmv2Rate() == null ? 0 : sysDept.getGmv2Rate();
			WmDeptGMVs.DayOfMonthRecord record = new WmDeptGMVs.DayOfMonthRecord();
			record.setStatisticsDay(String.valueOf(today.getDayOfMonth()));
			record.setGmv1Rate(gmv1Rate);
			record.setGmv2Rate(gmv2Rate);
			record.setGmv1(userScoreSum);
			record.setGmv2(settleNoteSum);
			record.setRenlijiaServiceChargeRate(renlijiaServiceChargeRate);
			record.setIncome(Math.round(settleNoteSum * gmv2Rate / 10000.0));

			WmDeptGMVs deptGMVs = new WmDeptGMVs();
			deptGMVs.setDeptId(sysDept.getDeptId());
			deptGMVs.setYear(String.valueOf(today.getYear()));
			deptGMVs.setMonth(String.valueOf(today.getMonthValue()));
			deptGMVs.setGmv1Rate(gmv1Rate);
			deptGMVs.setGmv2Rate(gmv2Rate);
			deptGMVs.setGmv1(userScoreSum);
			deptGMVs.setGmv2(settleNoteSum);
			deptGMVs.setRenlijiaServiceChargeRate(sysDept.getRenlijiaServiceChargeRate());
			deptGMVs.setIncome(Math.round(settleNoteSum * gmv2Rate / 10000.0));
			deptGMVs.setRecordList(new ArrayList<WmDeptGMVs.DayOfMonthRecord>() {{
				add(record);
			}});
			deptGMVsList.add(deptGMVs);

		});

		// 保存到数据库
		saveGMVsToDb(deptGMVsList, today);
	}

	/**
	 * 保存数据到数据库
	 *
	 * @param deptGMVsList
	 * @param today
	 */
	@Override
	public void saveGMVsToDb(List<WmDeptGMVs> deptGMVsList, LocalDate today) {
		deptGMVsList.forEach(wmDeptGMVs -> {
			// 主表
			WmDeptGmv deptGmv = wmDeptGmvService.getOne(Wrappers.<WmDeptGmv>lambdaQuery()
					.eq(WmDeptGmv::getDeptId, wmDeptGMVs.getDeptId())
					.eq(WmDeptGmv::getYear, wmDeptGMVs.getYear())
					.eq(WmDeptGmv::getMonth, wmDeptGMVs.getMonth()));
			// 子表每日的数据
			WmDeptGMVs.DayOfMonthRecord record = wmDeptGMVs.getRecordList().get(0);

			if (deptGmv == null) {
				// 保存主表
				deptGmv = new WmDeptGmv();
				deptGmv.setDeptId(wmDeptGMVs.getDeptId());
				deptGmv.setYear(wmDeptGMVs.getYear());
				deptGmv.setMonth(wmDeptGMVs.getMonth());
				deptGmv.setGmv1(wmDeptGMVs.getGmv1());
				deptGmv.setGmv1Rate(wmDeptGMVs.getGmv1Rate());
				deptGmv.setGmv2(wmDeptGMVs.getGmv2());
				deptGmv.setGmv2Rate(wmDeptGMVs.getGmv2Rate());
				deptGmv.setRenlijiaServiceChargeRate(wmDeptGMVs.getRenlijiaServiceChargeRate());
				deptGmv.setIncome(wmDeptGMVs.getIncome());
				deptGmv.setUpdateTime(today.atStartOfDay());
				wmDeptGmvService.save(deptGmv);
			} else {
				// 更新GMV
				deptGmv.setGmv1(wmDeptGMVs.getGmv1());
				deptGmv.setGmv1Rate(wmDeptGMVs.getGmv1Rate());
				deptGmv.setGmv2(wmDeptGMVs.getGmv2());
				deptGmv.setGmv2Rate(wmDeptGMVs.getGmv2Rate());
				deptGmv.setRenlijiaServiceChargeRate(wmDeptGMVs.getRenlijiaServiceChargeRate());
				deptGmv.setIncome(wmDeptGMVs.getIncome());
				deptGmv.setUpdateTime(today.atStartOfDay());
				wmDeptGmvService.updateById(deptGmv);
			}
			int id = deptGmv.getId();
			// 保存记录表
			WmDeptGmvRecord deptGmvRecord = new WmDeptGmvRecord();
			deptGmvRecord.setGmvId(id);
			deptGmvRecord.setStatisticsDay(record.getStatisticsDay());
			deptGmvRecord.setGmv1(record.getGmv1());
			deptGmvRecord.setGmv1Rate(record.getGmv1Rate());
			deptGmvRecord.setGmv2(record.getGmv2());
			deptGmvRecord.setGmv2Rate(record.getGmv2Rate());
			deptGmvRecord.setRenlijiaServiceChargeRate(record.getRenlijiaServiceChargeRate());
			deptGmvRecord.setIncome(record.getIncome());
			wmDeptGmvRecordService.save(deptGmvRecord);

			// 判断如果是第一天，则更新上个月的deptGmv（因为每个月的第一天存的是上个月的完整数据）
			if (record.getStatisticsDay().equals("1")) {
				LocalDate lastMonth = today.minusMonths(1);
				WmDeptGmv lastDeptGmv = wmDeptGmvService.getOne(Wrappers.<WmDeptGmv>lambdaQuery()
						.eq(WmDeptGmv::getDeptId, wmDeptGMVs.getDeptId())
						.eq(WmDeptGmv::getYear, String.valueOf(lastMonth.getYear()))
						.eq(WmDeptGmv::getMonth, String.valueOf(lastMonth.getMonthValue())));
				if (lastDeptGmv == null) {
					// 保存主表
					lastDeptGmv = new WmDeptGmv();
					lastDeptGmv.setDeptId(wmDeptGMVs.getDeptId());
					lastDeptGmv.setYear(wmDeptGMVs.getYear());
					lastDeptGmv.setMonth(wmDeptGMVs.getMonth());
					lastDeptGmv.setGmv1(wmDeptGMVs.getGmv1());
					lastDeptGmv.setGmv1Rate(wmDeptGMVs.getGmv1Rate());
					lastDeptGmv.setGmv2(wmDeptGMVs.getGmv2());
					lastDeptGmv.setGmv2Rate(wmDeptGMVs.getGmv2Rate());
					lastDeptGmv.setRenlijiaServiceChargeRate(wmDeptGMVs.getRenlijiaServiceChargeRate());
					lastDeptGmv.setIncome(wmDeptGMVs.getIncome());
					lastDeptGmv.setUpdateTime(today.atStartOfDay());
					wmDeptGmvService.save(lastDeptGmv);
				} else {
					// 更新GMV
					lastDeptGmv.setGmv1(wmDeptGMVs.getGmv1());
					lastDeptGmv.setGmv1Rate(wmDeptGMVs.getGmv1Rate());
					lastDeptGmv.setGmv2(wmDeptGMVs.getGmv2());
					lastDeptGmv.setGmv2Rate(wmDeptGMVs.getGmv2Rate());
					lastDeptGmv.setRenlijiaServiceChargeRate(wmDeptGMVs.getRenlijiaServiceChargeRate());
					lastDeptGmv.setIncome(wmDeptGMVs.getIncome());
					lastDeptGmv.setUpdateTime(today.atStartOfDay());
					wmDeptGmvService.updateById(lastDeptGmv);
				}
			}
		});
	}

	/**
	 * 将部分历史数据合并（如北疆区域、南疆区域、乌市区域都归类到新疆天山莲药业有限公司）
	 */
	@Override
	public void processSpecialGMVData() {
		for (String parentDeptName : convertMap.keySet()) {
			List<String> subDeptNames = convertMap.get(parentDeptName);
			// 根据父企业名称查询dept
			List<SysDept> parentDepts = sysDeptService.list(Wrappers.<SysDept>lambdaQuery().eq(SysDept::getName, parentDeptName));
			// 根据子企业名称查询dept
			List<SysDept> subDepts = sysDeptService.listAllDept().stream()
					.filter(sysDept -> subDeptNames.contains(sysDept.getName()))
					.collect(Collectors.toList());

			if (CollectionUtil.isNotEmpty(parentDepts) && CollectionUtil.isNotEmpty(subDepts)) {
				Integer parentDeptId = parentDepts.get(0).getDeptId();
				for (int year = 2020; year <= 2021; year++) {
					for (int month = 1; month <= 12; month++) {
						// 获取子数据的GMV，并求和
						long gmv1 = 0L;
						long gmv2 = 0L;
						long income = 0L;
						for (SysDept sysDept : subDepts) {
							WmDeptGmv deptGmv = wmDeptGmvService.getOne(Wrappers.<WmDeptGmv>lambdaQuery()
									.eq(WmDeptGmv::getYear, String.valueOf(year))
									.eq(WmDeptGmv::getMonth, String.valueOf(month))
									.eq(WmDeptGmv::getDeptId, sysDept.getDeptId()));
							if (deptGmv != null) {
								gmv1 += deptGmv.getGmv1() == null ? 0L : deptGmv.getGmv1();
								gmv2 += deptGmv.getGmv2() == null ? 0L : deptGmv.getGmv2();
								income += deptGmv.getIncome() == null ? 0L : deptGmv.getIncome();
							}
						}
						// 获取parent的GMV，累加子企业的GMV数据并更新
						WmDeptGmv deptGmv = wmDeptGmvService.getOne(Wrappers.<WmDeptGmv>lambdaQuery()
								.eq(WmDeptGmv::getYear, String.valueOf(year))
								.eq(WmDeptGmv::getMonth, String.valueOf(month))
								.eq(WmDeptGmv::getDeptId, parentDeptId));
						if (deptGmv != null) {
							gmv1 += deptGmv.getGmv1() == null ? 0L : deptGmv.getGmv1();
							gmv2 += deptGmv.getGmv2() == null ? 0L : deptGmv.getGmv2();
							income += deptGmv.getIncome() == null ? 0L : deptGmv.getIncome();
							// 备份GMV数据
							WmDeptGmv updateDeptGmv = new WmDeptGmv();
							updateDeptGmv.setId(deptGmv.getId());
							updateDeptGmv.setUpdateTime(LocalDateTime.now());
							updateDeptGmv.setGmv1(gmv1);
							updateDeptGmv.setGmv2(gmv2);
							updateDeptGmv.setIncome(income);
							wmDeptGmvService.updateById(updateDeptGmv);
						}
					}
				}
			}
		}
	}
}
