package com.huazheng.project.greenplum.service.impl;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;

import com.huazheng.project.greenplum.mapper.GPMapper;
import com.huazheng.project.hana.model.CAVThisMonth;
import com.huazheng.project.mssql3.mapper.Cinderellaw2Mapper;
import com.huazheng.project.mssql3.model.PersonComp;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.log4j.Log4j2;

@Log4j2
@Service
public class OtherJobServiceImpl {

	@Autowired
	private Cinderellaw2Mapper cinderellaw2Mapper;

	@Autowired
	private RedisTemplate<String, String> redis1Template;
	
	@Autowired
	private GPMapper gpMapper;

	public String getErrorInfoFromException(Exception e) {
		try {
			StringWriter sw = new StringWriter();
			PrintWriter pw = new PrintWriter(sw);
			e.printStackTrace(pw);
			return "\r\n" + sw.toString() + "\r\n";
		} catch (Exception e2) {
			return "bad getErrorInfoFromException";
		}
	}

	// 同步人员对照数据,非flink流程
	public void caPersonComp() {
		DefaultRedisScript<String> script = new DefaultRedisScript<String>();
		script.setResultType(String.class);
		script.setScriptSource(new ResourceScriptSource(new ClassPathResource("luascript/vbap4send.lua")));
		List<String> keys = Arrays.asList("huazheng:PersonComp:sendcount", "huazheng:PersonComp:rowids", "huazheng:list:PersonComp");

		ValueOperations<String, String> opsForValue = redis1Template.opsForValue();
		opsForValue.setIfAbsent("huazheng:PersonComp:sendcount", "0"); // 不存在则创建，存在则么有操作
		opsForValue.setIfAbsent("huazheng:PersonComp:receivecount", "0"); // 不存在则创建，存在则么有操作
		opsForValue.setIfAbsent("huazheng:PersonComp:rowids", "0"); // 不存在则创建，存在则么有操作
		Long sendcount = Long.valueOf(opsForValue.get("huazheng:PersonComp:sendcount"));
		Long receivecount = Long.valueOf(opsForValue.get("huazheng:PersonComp:receivecount"));
		if (sendcount - receivecount <= 20) { // 如果发送数和消费数的差小于5则往队列中写数据
			String rowids = opsForValue.get("huazheng:PersonComp:rowids"); // 标记id
			PersonComp personComp = PersonComp.builder().rowids(Long.valueOf(rowids)).build();
			List<PersonComp> list = cinderellaw2Mapper.selectPersonCompNew(personComp);
			if (!list.isEmpty()) {
				list.forEach(item -> {
					JSONObject json = JSONUtil.parseObj(item, false);
					String execute = redis1Template.execute(script, keys, item.getRowids().toString(), json.toString());
					log.info("标记时间回写 --> " + execute);
				});
			} else { 
				// 如果是空的，说明再源库中没有找到最新的数据
				// 由于此表没有没有自增列，同时数据量不多，所以把新增流程重置
				opsForValue.set("huazheng:PersonComp:sendcount", "0"); // 重置
				opsForValue.set("huazheng:PersonComp:receivecount", "0"); // 重置
				opsForValue.set("huazheng:PersonComp:rowids", "0"); // 重置
			}
		}
	}

	// 计算回款
	public void caPayment() {
		// 查询客户每月回款列表
		List<CAVThisMonth> groupList = gpMapper.selectCAVThisMonthByEveryMonth();
		// 按照客户和而货币分组
		Map<String, List<CAVThisMonth>> groupItemsCollect = groupList.stream().collect(Collectors.groupingBy(e -> e.getKunnr() + "#" + e.getWaers()));
		groupItemsCollect.forEach((kunnr2Waers, groupItems) -> {
			
			BigDecimal byhkTotal = new BigDecimal(0); // 当月当前累积回款
			BigDecimal byxseTotal = new BigDecimal(0); // 当月当前累积销售额
			
			// 遍历每个客户的每月回款清单，开始计算
			for (int i = 0; i < groupItems.size(); i++) {
				CAVThisMonth item = groupItems.get(i);
				String kunnr = item.getKunnr(); // 客户
				String waers = item.getWaers(); // 货币
				String budatb = item.getBudatb(); // 上个月

				// 抽取符合条件的上月的数据
				List<CAVThisMonth> collect = groupItems.stream() //
						.filter(pp -> pp.getKunnr().equals(kunnr)) //
						.filter(pp -> pp.getWaers().equals(waers)) //
						.filter(pp -> pp.getBudatb().equals(budatb)) //
						.collect(Collectors.toList());

				BigDecimal ljsyysk = new BigDecimal(0); // 上月，累积剩余应收款
				// 如果上月有数据
				if (!collect.isEmpty() && collect.get(0).getLjsyysk() != null) {
					ljsyysk = ljsyysk.add(collect.get(0).getLjsyysk()); // 上月，累积剩余应收款
				}

				BigDecimal byhk = item.getByhk(); // 当月回款
//				BigDecimal byxse = item.getByxse(); // 当月销售额
				item.setDyjhk(byhk.subtract(ljsyysk)); // 计算，当月净回款
//				item.setLjsyysk(byxse.subtract(item.getDyjhk())); // 计算，累积剩余应收款
				
				byhkTotal = byhkTotal.add(item.getByhk()); // 当月回款
				byxseTotal = byxseTotal.add(item.getByxse()); // 当月销售额
				item.setLjsyysk(byxseTotal.subtract(byhkTotal)); // 计算，累积剩余应收款
			}
			
			// 当月销售额0修正
			List<CAVThisMonth> zeroCollect = groupItems.stream().filter(pp -> pp.getByxse().compareTo(BigDecimal.ZERO) == 0).collect(Collectors.toList());
			if (!zeroCollect.isEmpty()) {
				zeroCollect.forEach(item -> {
					item.setDyjhk(new BigDecimal(0)); // 计算，当月净回款
					item.setLjsyysk(new BigDecimal(0)); // 计算，累积剩余应收款
				});
			}
		});
		// 数据输出
		groupList.forEach(item -> {
			CAVThisMonth target = gpMapper.selectCAVThisMonth(item); // 先查询数据是否存在
			String kunnr = item.getKunnr(); // 客户
			String waers = item.getWaers(); // 货币
			String budatd = item.getBudatd();
			String budatb = item.getBudatb();
			if (target == null) { // 并不存在
				gpMapper.insertCAVThisMonth(item); // 数据入库
				log.info("caPayment -> insert {}, {}, {}, {}", kunnr, waers, budatd, budatb);
			} else {
				String shash = SecureUtil.md5(JSONUtil.toJsonStr(item)); // 源库中数据的hash结果
				String thash = target.getHashResult(); // 数仓中数据的hash结果
				if (!shash.equals(thash)) { // 如果hash结果不一致
					item.setHashResult(shash);
					gpMapper.updateCAVThisMonth(item); // 更新数据到数仓中
					log.info("caPayment -> update {}, {}, {}, {}", kunnr, waers, budatd, budatb);
				}
			}
		});
	}
	
}
