/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.ldt.bills.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yeepay.yop.sdk.service.common.response.YopResponse;
import lombok.AllArgsConstructor;
import org.springblade.common.cache.PaymentCache;
import org.springblade.common.constant.CallbackServeUrl;
import org.springblade.common.enums.AppConstant;
import org.springblade.common.enums.OrderType;
import org.springblade.common.enums.PaymentScene;
import org.springblade.common.enums.PaymentType;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springblade.ldt.bills.entity.Bills;
import org.springblade.ldt.bills.entity.PointBills;
import org.springblade.ldt.bills.mapper.PointBillsMapper;
import org.springblade.ldt.bills.service.IBillsService;
import org.springblade.ldt.bills.service.IPointBillsService;
import org.springblade.ldt.bills.vo.PointBillCensusVO;
import org.springblade.ldt.bills.vo.PointBillsVO;
import org.springblade.ldt.bills.vo.YeePayAccountBalanceVO;
import org.springblade.ldt.mall.entity.Mall;
import org.springblade.ldt.mall.service.IMallService;
import org.springblade.payment.entity.SuccessParams;
import org.springblade.yeePay.common.YeePayConst;
import org.springblade.yeePay.common.YeepayApiConstant;
import org.springblade.yeePay.entity.saas.account.TransferOrderDto;
import org.springblade.yeePay.service.YeepaySaasService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * 服务实现类
 *
 * @author BladeX
 * @since 2021-09-23
 */
@AllArgsConstructor
@Service
public class PointBillsServiceImpl extends BaseServiceImpl<PointBillsMapper, PointBills> implements IPointBillsService {

	private IMallService mallService;
	private YeepaySaasService yeepaySaasService;
	private YeePayConst yeePayConst;
	private IBillsService billsService;

	@Override
	public IPage<PointBillsVO> selectPointBillsPage(IPage<PointBillsVO> page, PointBillsVO pointBills) {
		return page.setRecords(baseMapper.selectPointBillsPage(page, pointBills));
	}

	@Override
	public PointBillCensusVO censusData(BladeUser bladeUser) {
		PointBillCensusVO result = new PointBillCensusVO();
		if (!bladeUser.getTenantId().equals("000000")) {
			Mall mall = mallService.getOne(Wrappers.<Mall>lambdaQuery().select(Mall::getMerchantNo).eq(Mall::getTenantId, bladeUser.getTenantId()));
			if (mall != null && ObjectUtil.isNotEmpty(mall.getMerchantNo())) {
				//易宝余额
				YeePayAccountBalanceVO balanceVO = getYeePayAccountBalance(mall.getMerchantNo());
				result.setYeePayBalance(balanceVO.getBalance());
			}
		}

		//总金额
		QueryWrapper<PointBills> queryWrapper = new QueryWrapper<>();
		queryWrapper.select("sum(total_price) as totalPrice");
		result.setAccountsPayable(getData(queryWrapper));

		//已核销
		QueryWrapper<PointBills> queryYes = new QueryWrapper<>();
		queryYes.select("sum(total_price) as totalPrice").lambda().eq(PointBills::getIsCheak, "1");
		result.setHandledAmount(getData(queryYes));

		//未核销
		QueryWrapper<PointBills> queryNo = new QueryWrapper<>();
		queryNo.select("sum(total_price) as totalPrice").lambda().eq(PointBills::getIsCheak, "0");
		result.setUntreatedAmount(getData(queryNo));

		return result;
	}

	private String getData(QueryWrapper<PointBills> queryWrapper) {
		return ObjectUtil.isEmpty(getOne(queryWrapper)) ? "0.00" : getOne(queryWrapper).getTotalPrice().toPlainString();
	}

	@Override
	@Transactional
	public boolean handlePointBills(List<Long> ids, BladeUser bladeUser) {
		Mall mall = mallService.getOne(Wrappers.<Mall>lambdaQuery().select(Mall::getMerchantNo).eq(Mall::getTenantId, bladeUser.getTenantId()));

		if (mall == null || ObjectUtil.isEmpty(mall.getMerchantNo())) {
			throw new ServiceException("易宝商户号为空！");
		}

		YeePayAccountBalanceVO yeePayAccountBalance = getYeePayAccountBalance(mall.getMerchantNo());
		if (ObjectUtil.isEmpty(yeePayAccountBalance) || ObjectUtil.isEmpty(yeePayAccountBalance.getBalance())) {
			throw new ServiceException("余额不足，请充值处理！");
		}
		BigDecimal balance = BigDecimal.valueOf(Long.parseLong(yeePayAccountBalance.getBalance()));

		QueryWrapper<PointBills> query = new QueryWrapper<>();
		query.select("sum(total_price) as totalPrice").lambda()
			.eq(PointBills::getIsCheak, "0")
			.in(PointBills::getId, ids);

		PointBills pointBills = getOne(query);
		if (ObjectUtil.isEmpty(pointBills) && ObjectUtil.isEmpty(pointBills.getTotalPrice())) {
			throw new ServiceException("未找到记录！");
		}

		BigDecimal amount = pointBills.getTotalPrice();
		//判断余额是否可以进行核销操作
		if (balance.subtract(amount).compareTo(BigDecimal.ZERO) < 0) {
			throw new ServiceException("余额不足，请充值处理！");
		}

		//保存账单记录
		Bills bills = new Bills();
		bills.setPointNum(BigDecimal.ZERO);
		bills.setPointFee(BigDecimal.ZERO);
		bills.setBalanceNum(BigDecimal.ZERO);
		bills.setPrice(amount);
		bills.setTotalPrice(amount);
		bills.setCost(amount);
		bills.setPayPlugin(PaymentType.YEE_PAY.name());
		bills.setTitle("积分核销");
		bills.setPayStatus(AppConstant.BillPayStatus.待付款.name());
		bills.setPayScene(PaymentScene.TRANSFER.name());
		bills.setType(OrderType.MALL_CHARGE.name());
		bills.setDiscount(BigDecimal.ONE);
		bills.setPayId(bladeUser.getUserId());
		bills.setBillDesc(JSON.toJSONString(ids));//暂时存放需要核销的积分记录id
		bills.setTenantId(bladeUser.getTenantId());
		bills.setMallId(mall.getId());
		billsService.saveOrUpdate(bills);

		transfer(bills, mall);
		return true;
	}

	/**
	 * 积分核销，向易宝发起商户或商场账户扣费
	 */
	private void transfer(Bills bills, Mall mall) {
		String requestNo = IdUtil.simpleUUID();
		TransferOrderDto transferOrderDto = TransferOrderDto.builder()
			.fromMerchantNo(mall.getMerchantNo())
			.toMerchantNo(yeePayConst.getPlatformServiceNo())
			.orderAmount(bills.getPrice().toPlainString())
			.requestNo(requestNo)
			.usage("积分交易核销！")
			.feeChargeSide(YeepayApiConstant.feeChargeSide.INSIDE)
			.notifyUrl(CallbackServeUrl.CALL_BACK_SERVE_URL + "/payment/callback/YEE_PAY")
			.build();

		YopResponse yopResponse = yeepaySaasService.transferOrder(transferOrderDto);
		JSONObject res = JSON.parseObject(yopResponse.getStringResult());
		if (!Objects.equals(res.getString("returnCode"), "UA00000")) {
			throw new ServiceException(res.getString("returnMsg"));
		}

		//支付参数
		SuccessParams successParams  = SuccessParams.builder()
			.orderType(OrderType.MALL_CHARGE.name())
			.status(AppConstant.BillPayStatus.待付款.name())
			.bills(bills)
			.res(res)
			.build();

		PaymentCache.putSuccessParams(Convert.toStr(successParams.getBills().getId()), successParams);
	}

	/**
	 * 获取易宝余额信息
	 */
	private YeePayAccountBalanceVO getYeePayAccountBalance(String merchantNo) {
		YeePayAccountBalanceVO balanceVO = new YeePayAccountBalanceVO();
		YopResponse yopResponse = yeepaySaasService.accountBalanceQuery(merchantNo);
		if (ObjectUtil.isNotEmpty(yopResponse)) {
			balanceVO = JSON.parseObject(yopResponse.getStringResult(), YeePayAccountBalanceVO.class);
		}
		return balanceVO;
	}
}
