package cn.superdesk.uniorder.service.accounting.unified.customer.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.superdesk.uniorder.common.enums.common.CommonAccountingDateTypeEnum;
import cn.superdesk.uniorder.common.json.AnJsonUtils;
import cn.superdesk.uniorder.service.setting.UnifiedSnConfigService;
import cn.superdesk.uniorder.common.numerical.AnCollectionUtils;
import cn.superdesk.uniorder.common.enums.common.CommonAccountingStateEnum;
import cn.superdesk.uniorder.common.enums.accounting.customer.AccountingOrderCustomerAccountingStatusEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderBackAccountStatusEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderDimCreateByEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderInvoiceApplyStatusEnum;
import cn.superdesk.uniorder.dao.entity.accounting.unified.customer.AccountingUnifiedCustomer;
import cn.superdesk.uniorder.dao.entity.accounting.unified.customer.AccountingUnifiedCustomerXGoods;
import cn.superdesk.uniorder.dao.entity.base.UnifiedOrder;
import cn.superdesk.uniorder.dao.entity.base.UnifiedOrderGoods;
import cn.superdesk.uniorder.dao.entity.invoice.common.InvoiceBankInfo;
import cn.superdesk.uniorder.dao.mapper.accounting.unified.customer.*;
import cn.superdesk.uniorder.dao.mapper.base.UnifiedOrderGoodsMapperEx;
import cn.superdesk.uniorder.dao.mapper.base.UnifiedOrderMapper;
import cn.superdesk.uniorder.dao.mapper.base.UnifiedOrderMapperEx;
import cn.superdesk.uniorder.dao.mapper.base.UnifiedOrderReturnGoodsMapperEx;
import cn.superdesk.uniorder.dao.mapper.invoice.customer.InvoiceApplyMapperEx;
import cn.superdesk.uniorder.dao.mapper.organisation.SysEnterpriseMapperEx;
import cn.superdesk.uniorder.dao.mapper.organisation.SysOrganizationMapperEx;
import cn.superdesk.uniorder.dao.mapper.scheduler.SysQuartzScheduleTaskStatementOfAccountMapper;
import cn.superdesk.uniorder.dao.mapper.sys.SysOderUserMapperEx;
import cn.superdesk.uniorder.dao.mapper.sys.SysOrderMapper;
import cn.superdesk.uniorder.dao.mapper.invoice.common.InvoiceBankInfoMapperEx;
import cn.superdesk.uniorder.common.security.dto.LoginSysUser;
import cn.superdesk.uniorder.dto.param.accounting.unified.customer.UnifiedCustomerCreateDimGoodsParam;
import cn.superdesk.uniorder.dto.param.accounting.unified.customer.UnifiedCustomerCreateDimGoodsParamJsonStruct;
import cn.superdesk.uniorder.service.accounting.unified.customer.AccountingUnifiedCustomerOrderGoodsService;
import cn.superdesk.uniorder.service.accounting.unified.customer.AccountingUnifiedCustomerOrderService;
import cn.superdesk.uniorder.service.accounting.unified.customer.AccountingUnifiedCustomerServiceOpCreateDimGoods;
import cn.superdesk.uniorder.service.accounting.unified.customer.AccountingUnifiedCustomerXGoodsService;
import cn.superdesk.uniorder.service.order.base.UnifiedOrderCreditService;
import cn.superdesk.uniorder.service.order.base.UnifiedOrderGoodsService;
import cn.superdesk.uniorder.service.order.base.UnifiedOrderService;
import cn.superdesk.uniorder.service.invoice.common.InvoiceBankInfoService;
import cn.superdesk.uniorder.common.lamda.AnLamdaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;


/**
 * @Description: 客户结算 对账单 重构 拆分 创建部分
 * @Author: linjinyu
 * @CreateDate: 2021/1/20 下午3:45
 * @UpdateUser: linjinyu
 * @UpdateDate: 2021/1/20 下午3:45
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Slf4j
@Service
public class AccountingUnifiedCustomerServiceOpCreateDimGoodsImpl implements AccountingUnifiedCustomerServiceOpCreateDimGoods {

	@Autowired
	private AccountingUnifiedCustomerMapper      accountingUnifiedCustomerMapper;
	@Autowired
	private AccountingUnifiedCustomerMapperEx    accountingUnifiedCustomerMapperEx;
	@Autowired
	private AccountingUnifiedCustomerMapperExSys accountingUnifiedCustomerMapperExSys;

	@Autowired
	private AccountingUnifiedCustomerXGoodsMapper  accountingUnifiedCustomerXGoodsMapper;
	@Autowired
	private AccountingUnifiedCustomerXGoodsService accountingUnifiedCustomerXGoodsService;


	/****************************************** 对账单 订单 商品 表 将要弃用 start ******************************************/
	@Autowired
	private AccountingUnifiedCustomerOrderMapper   accountingUnifiedCustomerOrderMapper;
	@Autowired
	private AccountingUnifiedCustomerOrderMapperEx accountingUnifiedCustomerOrderMapperEx;

	@Autowired
	private AccountingUnifiedCustomerOrderGoodsMapper   accountingUnifiedCustomerOrderGoodsMapper;
	@Autowired
	private AccountingUnifiedCustomerOrderGoodsMapperEx accountingUnifiedCustomerOrderGoodsMapperEx;

	@Autowired
	private AccountingUnifiedCustomerOrderService      accountingUnifiedCustomerOrderService;
	@Autowired
	private AccountingUnifiedCustomerOrderGoodsService accountingUnifiedCustomerOrderGoodsService;

	/****************************************** 对账单 订单 商品 表 将要弃用   end ******************************************/

	@Autowired
	private InvoiceBankInfoMapperEx unifiedBankInfoMapper;


	@Autowired
	private SysOrderMapper      sysOrderMapper;
	@Autowired
	private SysOderUserMapperEx sysOderUserMapper;

	@Autowired
	private UnifiedOrderMapper              unifiedOrderMapper;
	@Autowired
	private UnifiedOrderMapperEx            unifiedOrderMapperEx;
	@Autowired
	private UnifiedOrderGoodsMapperEx       unifiedOrderGoodsMapperEx;
	@Autowired
	private UnifiedOrderReturnGoodsMapperEx unifiedOrderReturnGoodsMapperEx;


	@Autowired
	private UnifiedOrderService       unifiedOrderService;
	@Autowired
	private UnifiedOrderGoodsService  unifiedOrderGoodsService;
	@Autowired
	private UnifiedOrderCreditService unifiedOrderCreditService;

	@Autowired
	private SysQuartzScheduleTaskStatementOfAccountMapper sysQuartzScheduleTaskStatementOfAccountMapper;

	@Autowired
	private SysEnterpriseMapperEx   sysEnterpriseMapperEx;
	@Autowired
	private SysOrganizationMapperEx sysOrganizationMapper;

	@Autowired
	private InvoiceApplyMapperEx invoiceApplyMapperEx;

	@Autowired
	private InvoiceBankInfoService invoiceBankInfoService;


	@Autowired
	private UnifiedSnConfigService unifiedSnConfigService;


	/****************************************** 对账单 创建 start ******************************************/

	/**
	 * TODO 目前这个方法没办法区分 是任务还是人工的 还有的问题就是 目前这个对账单用的是下单时间来弄的,不稳定 mark by linjinyu at 20210916
	 * 1. 如果是任务的,要把处理问题输出,关联到任务报告里边
	 * 2. 如果是人工的,也得把反馈反馈到前端
	 *
	 * @param unifiedCustomerCreateDimGoodsParam
	 * @param loginSysUser
	 * @return
	 */
	@Override
	public AccountingUnifiedCustomer opCreateAccountingDimGoodsPreProcess(UnifiedCustomerCreateDimGoodsParam unifiedCustomerCreateDimGoodsParam, LoginSysUser loginSysUser) {


		/****************************************** 添加检查 mark by linjinyu at 20210125 start ******************************************/
		//		List<UnifiedCustomerCreateDimGoodsParamJsonStruct> requestParams = JsonUtils.toList(unifiedCustomerCreateDimGoodsParam.getJsonStr(), UnifiedCustomerCreateDimGoodsParamJsonStruct.class);
		List<UnifiedCustomerCreateDimGoodsParamJsonStruct> requestParams = unifiedCustomerCreateDimGoodsParam.getJsonStr();

		log.info("客户结算 创建对账单(商品维度) 包体 {}", AnJsonUtils.toJson(requestParams));

		if (AnCollectionUtils.isEmpty(requestParams)) {
			// TODO 记录错误-传过来的数据为空
			return null;
		}


		/****************************************** 过虑要对账商品中是否有已对账单 mark by linjinyu at 20210125 start ******************************************/

		List<Long> processSysUnifiedOrderGoodsIds = requestParams.stream()
				.filter(o -> null != o.getUnifiedOrderGoodsId())
				.filter(AnLamdaUtils.distinctByKey(o -> o.getUnifiedOrderGoodsId()))
				.map(UnifiedCustomerCreateDimGoodsParamJsonStruct::getUnifiedOrderGoodsId)
				.collect(Collectors.toList());

		List<UnifiedOrderGoods> processUnifiedOrderGoodsList = unifiedOrderGoodsService.findBySysUnifiedOrderGoodsIds(processSysUnifiedOrderGoodsIds);

		/****************************************** 过虑已对账商品 start ******************************************/

		List<Predicate<UnifiedOrderGoods>> predicatesUnifiedOrderGoodsByAccountingStateCustomerEq1 = new ArrayList<>();
		predicatesUnifiedOrderGoodsByAccountingStateCustomerEq1.add(r -> r.getAccountingStateCustomer() != null && r.getAccountingStateCustomer() == 1);
		List<UnifiedOrderGoods> predicatesUnifiedOrderGoodsByAccountingStateCustomerEq1Filter = AnLamdaUtils.filters(processUnifiedOrderGoodsList, predicatesUnifiedOrderGoodsByAccountingStateCustomerEq1);

		if (AnCollectionUtils.isNotEmpty(predicatesUnifiedOrderGoodsByAccountingStateCustomerEq1Filter)) {
			// TODO 记录错误-传过来的数据-包含已对账商品
			return null;
		}

		/****************************************** 过虑已对账商品   end ******************************************/

		/****************************************** 核算 对账单 总金额 mark by linjinyu at 20210125 start ******************************************/
		BigDecimal goodsAmount = processUnifiedOrderGoodsList
				.stream()
				.map(item -> item.getPrice() == null ? BigDecimal.ZERO : item.getPrice().multiply(new BigDecimal(item.getQuantity())))
				.reduce(BigDecimal.ZERO, BigDecimal::add);
		BigDecimal goodsCostAmount = processUnifiedOrderGoodsList
				.stream()
				.map(item -> item.getCostPrice() == null ? BigDecimal.ZERO : item.getCostPrice().multiply(new BigDecimal(item.getQuantity())))
				.reduce(BigDecimal.ZERO, BigDecimal::add);

		unifiedCustomerCreateDimGoodsParam.setAccountingAmount(goodsAmount);

		/****************************************** 核算 对账单 订单数 mark by linjinyu at 20210125 start ******************************************/

		List<Long> processUnifiedOrderIds = requestParams.stream().filter(AnLamdaUtils.distinctByKey(o -> o.getUnifiedOrderId())).map(o -> o.getUnifiedOrderId()).collect(Collectors.toList());

		unifiedCustomerCreateDimGoodsParam.setOrderQuantity(processUnifiedOrderIds.size());

		/****************************************** 核算 对账单 联系人信息 mark by linjinyu at 20210125 start ******************************************/

		List<UnifiedOrder> processUnifiedOrderList = unifiedOrderService.findBySysUnifiedOrderIds(processUnifiedOrderIds);

		if (null == unifiedCustomerCreateDimGoodsParam.getPurchaseUserId()) {

			UnifiedOrder sample = processUnifiedOrderList.get(0);

			unifiedCustomerCreateDimGoodsParam.setServiceNo(sample.getServiceNo());
			unifiedCustomerCreateDimGoodsParam.setPurchaseUserId(sample.getPurchaseUserId());
			unifiedCustomerCreateDimGoodsParam.setPurchaseUserName(sample.getPurchaseUserName());
			unifiedCustomerCreateDimGoodsParam.setPurchasePhone(sample.getPurchasePhone());

		}

		/****************************************** 核算 bankinfo mark by linjinyu at 20210125 start ******************************************/

		if (ObjectUtil.isNull(unifiedCustomerCreateDimGoodsParam.getBankInfoId())) {

			InvoiceBankInfo invoiceBankInfoEntity = invoiceBankInfoService.getByDefault();

			if (ObjectUtil.isNull(invoiceBankInfoEntity)) {
				// TODO 记录错误-传过来的数据-没有Bankinfo
				return null;
			} else {
				unifiedCustomerCreateDimGoodsParam.setBankInfoId(invoiceBankInfoEntity.getId());
			}
		}

		/****************************************** 构建 对账单 信息 start ******************************************/

		AccountingUnifiedCustomer accountingUnifiedCustomer = new AccountingUnifiedCustomer();

		// TODO 写死 这个是周期类型？1-发货时间;2-下单时间;3-完成时间; 默认为 下单时间
		accountingUnifiedCustomer.setDateType(CommonAccountingDateTypeEnum.下单时间.getKey());
		accountingUnifiedCustomer.setStartTime(unifiedCustomerCreateDimGoodsParam.getStartTime());
		accountingUnifiedCustomer.setEndTime(unifiedCustomerCreateDimGoodsParam.getEndTime());

		accountingUnifiedCustomer.setCycleBeginTime(unifiedCustomerCreateDimGoodsParam.getStartTime());
		accountingUnifiedCustomer.setCycleEndTime(unifiedCustomerCreateDimGoodsParam.getEndTime());

		//accountingUnifiedCustomer.setPurchaseAddress(orders.get(0).getAddressAddress());
		//accountingUnifiedCustomer.setInvoiceCompanyName(orders.get(0).get());

		accountingUnifiedCustomer.setCreateTime(DateUtil.date());
		accountingUnifiedCustomer.setCreateUserId(loginSysUser.getSysUserId());
		accountingUnifiedCustomer.setUpdateTime(DateUtil.date());
		accountingUnifiedCustomer.setUpdateUserId(loginSysUser.getSysUserId());

		// add 20200110
		// TODO 写死 支付类型
		accountingUnifiedCustomer.setPayType(0);
		// TODO 写死 支付状态
		accountingUnifiedCustomer.setPayStatus(2);


		accountingUnifiedCustomer.setInvoiceStatus(AccountingOrderInvoiceApplyStatusEnum.未申请.getKey());
		// 新版 3-待提交
		accountingUnifiedCustomer.setAccountingStatus(AccountingOrderCustomerAccountingStatusEnum.待提交.getKey());
		accountingUnifiedCustomer.setBackAccountStatus(AccountingOrderBackAccountStatusEnum.未回款.getKey());


		/****************************************** TODO 再去细化 mark by linjinyu at 202012242028 start ******************************************/

		// TODO 错错错 哪就不是错
		accountingUnifiedCustomer.setEnterpriseId(unifiedCustomerCreateDimGoodsParam.getOutVirtId());
		accountingUnifiedCustomer.setAccountingAmount(unifiedCustomerCreateDimGoodsParam.getAccountingAmount());
		accountingUnifiedCustomer.setQuantityOrder(unifiedCustomerCreateDimGoodsParam.getOrderQuantity());

		// 不自动发 邮件
//		accountingUnifiedCustomer.setIsSendEmail(unifiedCustomerCreateDimGoodsParam.getIsSendEmail());
//		accountingUnifiedCustomer.setSendEmailTime(DateUtil.date());

		// 当手动 创建 对账单的时候 订单维度的 有可能 存多个 商品维度已经作了过滤 所以 不存在这个问题
		accountingUnifiedCustomer.setServiceNo(unifiedCustomerCreateDimGoodsParam.getServiceNo());

		// 修正为 读配置？当发现不是唯一的情况下
		accountingUnifiedCustomer.setBankInfoId(unifiedCustomerCreateDimGoodsParam.getBankInfoId());

		accountingUnifiedCustomer.setPurchaseUserId(unifiedCustomerCreateDimGoodsParam.getPurchaseUserId());
		accountingUnifiedCustomer.setPurchaseUserName(unifiedCustomerCreateDimGoodsParam.getPurchaseUserName());
		accountingUnifiedCustomer.setPurchasePhone(unifiedCustomerCreateDimGoodsParam.getPurchasePhone());


		/****************************************** TODO 再去细化 mark by linjinyu at 202012242028 start ******************************************/


		/****************************************** 构建 对账单 信息   end ******************************************/


		return opCreateAccountingDimGoods(accountingUnifiedCustomer, requestParams);
	}

	/**
	 * 效率优化 mark by linjinyu at 20211203
	 *
	 * @param accountingUnifiedCustomer
	 * @param requestParams
	 * @return
	 */
	// statementOfAccount
	@Transactional
	@Override
	public AccountingUnifiedCustomer opCreateAccountingDimGoods(AccountingUnifiedCustomer accountingUnifiedCustomer, List<UnifiedCustomerCreateDimGoodsParamJsonStruct> requestParams) {

		accountingUnifiedCustomer.setDimCreateBy(AccountingOrderDimCreateByEnum.商品.getKey());
		// 用于标记生成逻辑:10-早期;20-改版202012
		accountingUnifiedCustomer.setLogicMode(20);


		accountingUnifiedCustomer.setAccountingOrderSn(unifiedSnConfigService.getCustomerStatementOfAccountSnBySnowflake(""));

		// 对账单 信息在上一步已经好了
		accountingUnifiedCustomerMapper.insert(accountingUnifiedCustomer);

		/****************************************** 差异部分 Dim Goods start ******************************************/


		List<Long> processSysUnifiedOrderIds      = requestParams.stream().filter(o -> null != o.getUnifiedOrderId()).filter(AnLamdaUtils.distinctByKey(o -> o.getUnifiedOrderId())).map(UnifiedCustomerCreateDimGoodsParamJsonStruct::getUnifiedOrderId).collect(Collectors.toList());
		List<Long> processSysUnifiedOrderGoodsIds = requestParams.stream().filter(o -> null != o.getUnifiedOrderGoodsId()).filter(AnLamdaUtils.distinctByKey(o -> o.getUnifiedOrderGoodsId())).map(UnifiedCustomerCreateDimGoodsParamJsonStruct::getUnifiedOrderGoodsId).collect(Collectors.toList());
		List<Long> processOutGoodsIds             = requestParams.stream().filter(o -> null != o.getGoodsId()).filter(AnLamdaUtils.distinctByKey(o -> o.getGoodsId())).map(UnifiedCustomerCreateDimGoodsParamJsonStruct::getGoodsId).collect(Collectors.toList());

		List<String> processOrderSn = unifiedOrderService.convertSysUnifiedOrderIds2OrderSn(processSysUnifiedOrderIds);

		Map<Long, String>            mapSysUnifiedOrderId2OrderSn     = unifiedOrderService.convertSysUnifiedOrderIds2MapSysUnifiedOrderId2OrderSn(processSysUnifiedOrderIds);
		Map<Long, UnifiedOrderGoods> mapSysUnifiedOrderGoodsId2Entity = unifiedOrderGoodsService.convertSysUnifiedOrderGoodsIds2MapSysUnifiedOrderGoodsId2Entity(processSysUnifiedOrderGoodsIds);

		Map<String, Object> params = new HashMap<>();
		params.put("dimCreateBy", AccountingOrderDimCreateByEnum.商品.getKey());
		params.put("accountingOrderSn", accountingUnifiedCustomer.getAccountingOrderSn());
		params.put("ids", processSysUnifiedOrderIds); // 这个是 uo.id

		List<AccountingUnifiedCustomerXGoods> processAccountingUnifiedCustomerXGoodsList = new ArrayList<>();

		int countGoodscChangeError = 0;

		// 对账单 X [订单] X 商品 TODO mark by linjinyu 20201029 由于时间赶 先这样弄 一条条没效率
		for (UnifiedCustomerCreateDimGoodsParamJsonStruct structItem : requestParams) {

			log.info("UnifiedCustomerCreateDimGoodsParamJsonStruct goodsId is null : {}", AnJsonUtils.toJson(structItem));

			AccountingUnifiedCustomerXGoods xGoods = new AccountingUnifiedCustomerXGoods();

			xGoods.setDimCreateBy(AccountingOrderDimCreateByEnum.商品.getKey());

			xGoods.setAccountingOrderId(accountingUnifiedCustomer.getId());
			xGoods.setAccountingOrderSn(accountingUnifiedCustomer.getAccountingOrderSn());

			xGoods.setUnifiedOrderId(structItem.getUnifiedOrderId());
			xGoods.setOrderSn(mapSysUnifiedOrderId2OrderSn.get(structItem.getUnifiedOrderId()));


			/****************************************** 处理异常 start ******************************************/

			if (null != mapSysUnifiedOrderGoodsId2Entity.get(structItem.getUnifiedOrderGoodsId())) {
				xGoods.setUnifiedOrderGoodsId(structItem.getUnifiedOrderGoodsId());
				xGoods.setGoodsId(mapSysUnifiedOrderGoodsId2Entity.get(structItem.getUnifiedOrderGoodsId()).getGoodsId());
				xGoods.setOutSnapshotOrderGoodsId(mapSysUnifiedOrderGoodsId2Entity.get(structItem.getUnifiedOrderGoodsId()).getOutSnapshotOrderGoodsId());
			} else {
				countGoodscChangeError++;
			}


			xGoods.setCreateUserId(1L);
			xGoods.setCreateTime(DateUtil.date());
			xGoods.setUpdateUserId(1L);
			xGoods.setCreateTime(DateUtil.date());

			processAccountingUnifiedCustomerXGoodsList.add(xGoods);

		}

		if (countGoodscChangeError > 0) {

			// 生成 report
			return null;
		}

		// 重构 再再 mark by linjinyu at 20210202 修改为 批量插入
		accountingUnifiedCustomerXGoodsService.insertBatch(processAccountingUnifiedCustomerXGoodsList);

		// 更新 订单 客户对账状态 -> 已对账
		unifiedOrderService.updateAccountingStateCustomerByOrderSns(processOrderSn, CommonAccountingStateEnum.已对账);

		// 更新 商品 客户对账状态 -> 已对账
		unifiedOrderGoodsService.updateAccountingStateCustomerByOrderSnAndSysUnifiedOrderGoodsIds(processOrderSn, processSysUnifiedOrderGoodsIds, CommonAccountingStateEnum.已对账);

		// 更新 流水 客户对账状态  -> 已对账 20200925 客户结算 创建对账单 如果 积分 流水 有的话 关联 更新状态 为 已对账状态
//		unifiedOrderCreditService.updateAccountingStateCustomerByOrderSnAndOutGoodsIds(processOrderSn, processOutGoodsIds, CommonAccountingStateEnum.已对账);


		/****************************************** 差异部分 Dim Goods   end ******************************************/

		return accountingUnifiedCustomer;
	}
	/****************************************** 对账单 创建   end ******************************************/


}
