/*
 *      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.modules.guosen.userActivityStatistical.service.impl;


import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springblade.common.constant.SystemConstant;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.DigestUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.guosen.activity.entity.Activity;
import org.springblade.modules.guosen.activity.service.IActivityService;
import org.springblade.modules.guosen.hotDetail.service.IHotDetailService;
import org.springblade.modules.guosen.loginUser.entity.LoginUser;
import org.springblade.modules.guosen.loginUser.service.ILoginUserService;
import org.springblade.modules.guosen.loginUser.vo.LoginWebVO;
import org.springblade.modules.guosen.pointsProportion.service.IPointsProportionService;
import org.springblade.modules.guosen.rank.service.RankService;
import org.springblade.modules.guosen.userActivityStatistical.dto.RankQueryDTO;
import org.springblade.modules.guosen.userActivityStatistical.dto.UserUsableHotAndPoints;
import org.springblade.modules.guosen.userActivityStatistical.vo.MyBonusVO;
import org.springblade.modules.guosen.userActivityStatistical.dto.UserActivityStatisticalDTO;
import org.springblade.modules.guosen.userActivityStatistical.entity.UserActivityStatistical;
import org.springblade.modules.guosen.userActivityStatistical.mapper.UserActivityStatisticalMapper;
import org.springblade.modules.guosen.userActivityStatistical.service.IUserActivityStatisticalService;
import org.springblade.modules.guosen.userActivityStatistical.vo.UserActivityStatisticalVO;
import org.springblade.modules.guosen.userBank.entity.UserBank;
import org.springblade.modules.guosen.userBank.service.IUserBankService;
import org.springblade.modules.guosen.withdrawConfig.entity.WithdrawConfig;
import org.springblade.modules.guosen.withdrawConfig.service.IWithdrawConfigService;
import org.springblade.modules.guosen.withdrawRecords.entity.WithdrawRecords;
import org.springblade.modules.guosen.withdrawRecords.service.IWithdrawRecordsService;
import org.springblade.modules.system.service.IParamService;
import org.springblade.yeePay.entity.PayOrderDto;
import org.springblade.yeePay.service.YeePayService;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 *  服务实现类
 *
 * @author BladeX
 * @since 2021-06-20
 */
@Service
public class UserActivityStatisticalServiceImpl extends BaseServiceImpl<UserActivityStatisticalMapper, UserActivityStatistical> implements IUserActivityStatisticalService {

	@Resource @Lazy
	private ILoginUserService loginUserService;
	@Resource @Lazy
	private IActivityService activityService;
	@Resource
	private IWithdrawRecordsService withdrawRecordsService;
	@Resource
	private IPointsProportionService pointsProportionService;
	@Resource @Lazy
	private RankService rankService;
	@Resource
	private IUserBankService userBankService;
	@Resource
	private YeePayService yeePayService;
	@Resource
	private IParamService paramService;
	@Resource
	private StringRedisTemplate stringRedisTemplate;
	@Resource
	private IWithdrawConfigService withdrawConfigService;
	@Resource
	private IHotDetailService hotDetailService;

	@Override
	public IPage<UserActivityStatisticalVO> selectUserActivityStatisticalPage(IPage<UserActivityStatisticalVO> page, UserActivityStatisticalVO userActivityStatistical) {
		return page.setRecords(baseMapper.selectUserActivityStatisticalPage(page, userActivityStatistical));
	}
	@Override
	public void updateValue(UserActivityStatisticalDTO dto) {
		UserActivityStatistical userActivityStatistical = this.getOne(Condition.getQueryWrapper(new UserActivityStatistical()).lambda()
			.eq(UserActivityStatistical::getUserId, dto.getUserId())
			.eq(UserActivityStatistical::getActivityId, dto.getActivityId()));
		if (userActivityStatistical == null) {
			userActivityStatistical = new UserActivityStatistical();
			userActivityStatistical.setUserId(dto.getUserId());
			userActivityStatistical.setActivityId(dto.getActivityId());
		}
		//修改总热力
		if (dto.getTotalHotValue() != null) {
			BigDecimal totalHotValue = userActivityStatistical.getTotalHotValue();
			BigDecimal totalHotValueNew= totalHotValue == null || BigDecimal.ZERO.equals(totalHotValue)? dto.getTotalHotValue() : totalHotValue.add(dto.getTotalHotValue());
			userActivityStatistical.setTotalHotValue(totalHotValueNew);
		}
		//修改可用热力
		if (dto.getUsableHotValue() != null) {
			BigDecimal usableHotValue = userActivityStatistical.getUsableHotValue();
			BigDecimal usableHotValueNew= usableHotValue == null || BigDecimal.ZERO.equals(usableHotValue)? dto.getUsableHotValue() : usableHotValue.add(dto.getUsableHotValue());
			userActivityStatistical.setUsableHotValue(usableHotValueNew);
		}
		//修改总积分
		if (dto.getTotalPointsValue() != null) {
			BigDecimal totalPointsValue = userActivityStatistical.getTotalPointsValue();
			BigDecimal totalPointsValueNew= totalPointsValue == null || BigDecimal.ZERO.equals(totalPointsValue)? dto.getTotalPointsValue() : totalPointsValue.add(dto.getTotalPointsValue());
			userActivityStatistical.setTotalPointsValue(totalPointsValueNew);
		}
		//修改可用积分
		if (dto.getUsablePointsValue() != null) {
			BigDecimal usablePointsValue = userActivityStatistical.getUsablePointsValue();
			BigDecimal usablePointsValueNew= usablePointsValue == null || BigDecimal.ZERO.equals(usablePointsValue)? dto.getUsablePointsValue() : usablePointsValue.add(dto.getUsablePointsValue());
			userActivityStatistical.setUsablePointsValue(usablePointsValueNew);
		}
		//修改现金值
		if (dto.getUsableCash() != null) {
			//可提用现金和总的可提用现金增加值是相同的
			//只是提现的时候消耗了可提用现金,总可提用现金不变
			BigDecimal myUsableCash = userActivityStatistical.getUsableCash();
			BigDecimal usableCashNum= myUsableCash == null || BigDecimal.ZERO.equals(myUsableCash)? dto.getUsableCash() : myUsableCash.add(dto.getUsableCash());
			userActivityStatistical.setUsableCash(usableCashNum);
			userActivityStatistical.setTotalCash(usableCashNum);
		}
		//修改收到礼物的总现金
		if (dto.getTotalPresentCash() != null) {
			BigDecimal myTotalCash = userActivityStatistical.getTotalPresentCash();
			BigDecimal totalCashNum= myTotalCash == null || BigDecimal.ZERO.equals(myTotalCash)? dto.getTotalPresentCash() : myTotalCash.add(dto.getTotalPresentCash());
			userActivityStatistical.setTotalPresentCash(totalCashNum);
		}
		this.saveOrUpdate(userActivityStatistical);
	}

	@Override
	public MyBonusVO getBonus(Long userId) {
		MyBonusVO myBonusVO = new MyBonusVO();
		//可用热力值
		BigDecimal usableHotValue = BigDecimal.ZERO;
		//总可提现现金
		BigDecimal usableWithdraw = BigDecimal.ZERO;
		//已提用现金
		BigDecimal withdrawed = BigDecimal.ZERO;

		List<UserActivityStatistical> activityStatisticalList = this.list(Condition.getQueryWrapper(new UserActivityStatistical()).lambda()
			.eq(UserActivityStatistical::getUserId, userId));
		for (UserActivityStatistical item : activityStatisticalList) {
			usableHotValue = usableHotValue.add(item.getUsableHotValue());
			usableWithdraw = usableWithdraw.add(item.getUsableCash());
		}
		//已提用现金
		List<WithdrawRecords> list = withdrawRecordsService.list(Condition.getQueryWrapper(new WithdrawRecords()).lambda()
			.eq(WithdrawRecords::getUserId, userId)
			.eq(WithdrawRecords::getWithdrawStatus,1));
		for (WithdrawRecords withdrawRecords : list) {
			withdrawed = withdrawed.add(withdrawRecords.getCashValue());
		}
		//总兑换到账
		BigDecimal totalWithDraw = usableWithdraw.add(withdrawed);

		myBonusVO.setUsableHotValue(usableHotValue);
		myBonusVO.setUsableWithdraw(usableWithdraw);
		myBonusVO.setWithdrawed(withdrawed);
		myBonusVO.setTotalWithDraw(totalWithDraw);
		return myBonusVO;
	}

	@Override
	@Transactional
	public R withdraw(List<UserActivityStatistical> userActivityStatisticalList,String withdrawPassword) {
		List<WithdrawConfig> withdrawConfigList = withdrawConfigService.list();
		WithdrawConfig withdrawConfig = withdrawConfigList.get(0);

		//手续费承担方
		String feeChargeSide = withdrawConfig.getFeeChargeSide();
		//到账类型
		String receiveType = withdrawConfig.getReceiveType();
		//提现次数
		Integer withdrawTimes = withdrawConfig.getUserWithdrawTimes();
		//最小限额
		String withdrawMinimum = withdrawConfig.getWithdrawMinimum();

		Long userId = userActivityStatisticalList.get(0).getUserId();//用户id
		int withTimeInRedis = this.getWithTimeInRedis(userId);
		if (withTimeInRedis >= withdrawTimes) {
			return R.fail("当日已无提现次数");
		}
		//消耗的总热力值
		BigDecimal consumeTotalHotValue = BigDecimal.ZERO;
		//兑换的总现金
		BigDecimal consumeTotalCash = BigDecimal.ZERO;

		List<UserActivityStatistical> needUpdateUserActivityStatistical = new ArrayList<>();

		for (UserActivityStatistical statistical : userActivityStatisticalList) {
			UserActivityStatistical userActivityStatistical = this.getById(statistical.getId());
			//消耗的现金为
			BigDecimal consumeCash = statistical.getTotalCash();
			//兑换后的可提用现金为
			BigDecimal subtract = userActivityStatistical.getUsableCash().subtract(consumeCash);
			//如果小于0
			if (subtract.compareTo(BigDecimal.ZERO) == -1) {
				return R.fail("请输入正确的兑换金额");
			}
			//开始兑换
			userActivityStatistical.setUsableCash(subtract);
			//兑换后的可用热力值减少
			Activity activity = activityService.getById(statistical.getActivityId());
			//减少的热力值=要兑换的现金值除以比例
			BigDecimal consumeHotValue = consumeCash.divide(activity.getBonusProportion());
			userActivityStatistical.setUsableHotValue(userActivityStatistical.getUsableHotValue().subtract(consumeHotValue));
			needUpdateUserActivityStatistical.add(userActivityStatistical);
			//消耗的总热力值为
			consumeTotalHotValue = consumeTotalHotValue.add(consumeHotValue);
			//兑换的总现金为
			consumeTotalCash = consumeTotalCash.add(consumeCash);
		}
		//判断提现得最低额度
		BigDecimal withdraw_mini_num = StringUtil.isBlank(withdrawMinimum) ? BigDecimal.valueOf(10.00) : BigDecimal.valueOf(Double.parseDouble(withdrawMinimum));

		if (consumeTotalCash.compareTo(withdraw_mini_num) == -1) {
			//小于最低额度
			return R.fail("最低提现额度为：" + withdraw_mini_num+" 元");
		}
		//提现到银行卡
		UserBank  userBank = userBankService.getOne(Condition.getQueryWrapper(new UserBank()).lambda().eq(UserBank::getUserId, userId));
		if (userBank == null) {
			return R.fail("提现失败，用户未绑定银行卡");
		}

		if(userBank.getWithdrawPassword() == null){
			return R.fail("提现密码不能为空，请点击绑卡并设置提现密码");
		}

		if(!userBank.getWithdrawPassword().equals(DigestUtil.hex(withdrawPassword))){
			return R.fail("提现密码不正确");
		}

		String simpleUUID = IdUtil.simpleUUID();

		//获取用户信息
		String cardNo = userBank.getCardNo();
		LoginUser loginUser = loginUserService.getById(userId);
		//插入提现记录
		WithdrawRecords withdrawRecords = new WithdrawRecords();
		withdrawRecords.setRequestNo(simpleUUID);
		withdrawRecords.setOpenid(loginUser.getOpenid());
		withdrawRecords.setHotValue(consumeTotalHotValue);
		withdrawRecords.setCashValue(consumeTotalCash);
		withdrawRecords.setNote("热力值提现");
		withdrawRecords.setReceiverAccountNo(cardNo);
		withdrawRecords.setOrderAmount(consumeTotalCash.toString());
		withdrawRecords.setReceiveType(receiveType);
		withdrawRecords.setWithdrawStatus(0);//申请提现
		withdrawRecords.setUserId(userId);
		withdrawRecords.setUpdateAffair(JSONObject.toJSONString(needUpdateUserActivityStatistical));

		PayOrderDto transferDto = PayOrderDto.builder()
			.bankAccountType(userBank.getBankAccountType())
			.orderAmount(Double.parseDouble(consumeTotalCash.toString()))
			.feeChargeSide(feeChargeSide)
			.receiveType(receiveType)
			.receiverAccountName(userBank.getRealName())
			.receiverAccountNo(cardNo)
			.receiverBankCode(userBank.getBankType())
			.requestNo(simpleUUID).build();
		R r = yeePayService.payOrder(transferDto, null);
		JSONObject jsonObject = (JSONObject) r.getData();
		String status = jsonObject.getString("status");
		System.out.println("*******jsonObject"+jsonObject);
		if (r.getCode() == 400 || Objects.equals(status,"FAIL")) {
			withdrawRecords.setWithdrawStatus(2);//申请提现
			String returnMsg = jsonObject.getString("returnMsg");
			withdrawRecords.setFailReason(returnMsg);
			withdrawRecordsService.save(withdrawRecords);
			return R.data("提现失败," + returnMsg);
		}
		withdrawRecordsService.save(withdrawRecords);

		if (Objects.equals(status, "REQUEST_RECEIVE")) {
			return R.data("请求已接收");
		} else if (Objects.equals(status, "REQUEST_ACCEPT")) {
			return R.data("请求已受理");
		}else if(Objects.equals(status, "REMITING")){
			return R.data("银行处理中");
		}else{
			return R.data(true);
		}
	}

	@Override
	public UserUsableHotAndPoints getUsableHotAndPoints(Long userId,Long activityId) {
		UserActivityStatistical statistical = this.getOne(Condition.getQueryWrapper(new UserActivityStatistical()).lambda()
			.eq(UserActivityStatistical::getUserId, userId)
			.eq(UserActivityStatistical::getActivityId, activityId));

		Activity activity = activityService.getById(activityId);

		UserUsableHotAndPoints userUsableHotAndPoints = new UserUsableHotAndPoints();
		userUsableHotAndPoints.setUsablePoints(statistical.getUsablePointsValue());
		userUsableHotAndPoints.setUsableHot(statistical.getUsableHotValue());
		userUsableHotAndPoints.setHotProportion(activity.getBonusProportion());
		userUsableHotAndPoints.setPointsProportion(pointsProportionService.list().get(0).getPointsProportion());

		return userUsableHotAndPoints;
	}

	@Override
	public IPage getRank(RankQueryDTO rankQueryDTO, Query query) {
		String activityId = rankQueryDTO.getActivityId().toString();
		//将sql的页码转换为redis zSet的页码
		int current = query.getCurrent() == null ? 1 : query.getCurrent();
		int size = query.getSize()==null ? 10 : query.getSize();
		int start = (current - 1) * size;
		int end = current * size - 1;
		//查询的类型 0选手 1作品
		Integer type = rankQueryDTO.getType();
		List<LoginWebVO> loginWebVOS = rankService.reverseZRankWithRank(activityId, start, end, type);
		//模糊筛选
		String nickNameSearch = rankQueryDTO.getNickName();
		if (rankQueryDTO.getType() == 0 && nickNameSearch != null) {
			loginWebVOS = loginWebVOS.stream()
				.filter(item -> item.getNickName().contains(nickNameSearch)||nickNameSearch.contains(item.getNickName()))
				.collect(Collectors.toList());
		}
		String productionType = rankQueryDTO.getProductionType();
		if (rankQueryDTO.getType() == 1 && productionType != null) {
			//作品排名，需要根据榜单筛选
			loginWebVOS = loginWebVOS.stream()
				.filter(item -> item.getProduction().getPersonType().equals(productionType))
				.collect(Collectors.toList());
		}
		String productionSearch = rankQueryDTO.getProductionSearch();
		if (rankQueryDTO.getType() == 1 && productionSearch != null) {
			loginWebVOS = loginWebVOS.stream()
				.filter(item ->item.getProduction().getTitle().contains(productionSearch)
					||item.getProduction().getPersonName().contains(productionSearch)
					||item.getNickName().contains(productionSearch))
				.collect(Collectors.toList());
		}
		//page对象
		IPage page = new Page();
		page.setRecords(loginWebVOS);
		page.setCurrent(current);
		page.setSize(size);
		page.setTotal(rankService.getCount(activityId, type));
		return page;
	}

	@Override
	public List<UserActivityStatistical> selectPlayerList() {
		return baseMapper.selectPlayerList();
	}

	private int getWithTimeInRedis(Long userId) {
		String strWithDrawTime = stringRedisTemplate.boundValueOps(SystemConstant.WITHDRAW_KEY + userId).get();
		if (StringUtil.isBlank(strWithDrawTime)) {
			return 0;
		} else {
			return Integer.valueOf(strWithDrawTime);
		}
	}
}
