package org.springblade.gateway.active_gateway.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.jsonwebtoken.lang.Assert;
import org.apache.commons.lang3.ObjectUtils;
import org.springblade.common.utils.BeanPropertyUtil;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.gateway.active_gateway.exception.AppActiveProductException;
import org.springblade.gateway.active_gateway.service.AppActiveProductService;
import org.springblade.gateway.active_gateway.util.ActiveProductUtil;
import org.springblade.gateway.common_gateway.dto.ActiveSettingDto;
import org.springblade.gateway.common_gateway.util.PlatformSettingUtil;
import org.springblade.gateway.goods_gateway.exception.HelpGoodsException;
import org.springblade.gateway.heat_gateway.enums.HeatTypeEnum;
import org.springblade.gateway.point_gateway.enums.PointTypeEnum;
import org.springblade.sing.active.entity.ActiveHelpRecord;
import org.springblade.sing.active.entity.ActiveProductRecord;
import org.springblade.sing.active.entity.ActiveRecord;
import org.springblade.sing.active.service.IActiveHelpRecordService;
import org.springblade.sing.active.service.IActiveProductRecordService;
import org.springblade.sing.active.service.IActiveRecordService;
import org.springblade.sing.goods.entity.HelpGoods;
import org.springblade.sing.goods.service.IHelpGoodsService;
import org.springblade.sing.heat.entity.HeatRecord;
import org.springblade.sing.heat.entity.UserHeat;
import org.springblade.sing.heat.service.IHeatRecordService;
import org.springblade.sing.heat.service.IUserHeatService;
import org.springblade.sing.point.entity.PointRecord;
import org.springblade.sing.point.entity.UserPufaPoint;
import org.springblade.sing.point.service.IPointRecordService;
import org.springblade.sing.point.service.IUserPufaPointService;
import org.springblade.sing.user.entity.LoginUser;
import org.springblade.sing.user.service.ILoginUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Map;

/**
 * @Author: Silent
 * @Description
 * @Date: Created in 9:57 2021/11/9
 * @Modified By:
 */
@Service
public class AppActiveProductServiceImpl implements AppActiveProductService {
	@Autowired
	private IActiveHelpRecordService activeHelpRecordService;
	@Autowired
	private ILoginUserService loginUserService;
	@Autowired
	private IPointRecordService pointRecordService;
	@Autowired
	private IHeatRecordService heatRecordService;
	@Autowired
	private IActiveProductRecordService activeProductRecordService;
	@Autowired
	private IActiveRecordService activeRecordService;
	@Autowired
	private IHelpGoodsService helpGoodsService;
	@Autowired
	private PlatformSettingUtil platformSettingUtil;
	@Autowired
	private IUserHeatService userHeatService;
	@Autowired
	private IUserPufaPointService userPufaPointService;

	/**
	 * 活动助力
	 *
	 * @param activeHelpRecord
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void activeHelp(ActiveHelpRecord activeHelpRecord,String phone) {
		//获取作品
		ActiveProductRecord activeProductRecord = activeProductRecordService.getById(activeHelpRecord.getProductId());
		Assert.notNull(activeProductRecord, "没有找到作品");

		//判断作品是否禁用
		Assert.isTrue(Integer.valueOf(1).equals(activeProductRecord.getStatus()), "作品已被禁用");

		//获取登录用户
		LoginUser loginUser = loginUserService.getById(activeHelpRecord.getUserId());
		Assert.notNull(loginUser, "没有找到用户");

		//获取道具记录
		HelpGoods helpGoods = helpGoodsService.getById(activeHelpRecord.getHelpGoodsId());
		Assert.notNull(helpGoods, "没有找到该道具");

		//获取活动
		ActiveRecord activeRecord = activeRecordService.getById(activeProductRecord.getActiveId());
		Assert.notNull(activeRecord, "没有找到该活动");

		//判断活动是否开始(活动开始时间>当前时间)
		if (activeRecord.getStartTime().getTime() > DateUtil.now().getTime()) {
			throw new AppActiveProductException("活动还未开始哦~");
		}
		//判断当前活动是否结束(活动结束时间<当前时间)
		if (activeRecord.getEndTime().getTime() < DateUtil.now().getTime()) {
			throw new AppActiveProductException("活动已结束哦~");
		}

		//判断用户使用该道具对该活动助力次数是否到达上限
		userHelpCountCheck(activeHelpRecord, activeProductRecord, loginUser, helpGoods);

		//获取平台参数配置
		ActiveSettingDto activeSetting = platformSettingUtil.getActiveSetting();
		Assert.notNull(activeSetting, "平台没有配置投票参数");

		//更新用户普法积分
		if(!BigDecimal.ZERO.equals(helpGoods.getPoint())){
			userPuFaPointUpdate(activeHelpRecord, phone, activeSetting);
		}

		//更新活动作品的票数和热力值
		updateProductVoteAndHeat(activeHelpRecord, activeProductRecord, activeSetting);

		//修改活动作品信息
		Assert.isTrue(activeProductRecordService.updateById(activeProductRecord));

		//添加活动记录
		Assert.isTrue(activeHelpRecordService.save(activeHelpRecord), "投票失败");
	}

//	/**
//	 * 更新活动作品的票数和热力值
//	 * @param activeHelpRecord
//	 * @param activeProductRecord
//	 * @param activeSetting
//	 */
//	@Override
//	public void updateProductVoteAndHeat(ActiveHelpRecord activeHelpRecord, ActiveProductRecord activeProductRecord, ActiveSettingDto activeSetting) {
//		//修改活动热力值和票数
//		activeProductRecord.setVoteCount(activeProductRecord.getVoteCount() + 1);
//
//		//判断是否赠送热力值
//		if (ObjectUtils.isNotEmpty(activeSetting.getVoteAndHeatRate()) && !activeSetting.getVoteAndHeatRate().equals(BigDecimal.ZERO)) {
//			//查询参赛用户
//			LoginUser productUser = loginUserService.getOne(Wrappers.<LoginUser>lambdaQuery().eq(LoginUser::getPhone, activeProductRecord.getPhone()));
//			Assert.notNull(productUser, "没有找到该参赛选手");
//
//			//热力值=活动票数*热力值比例
//			BigDecimal heatValue = activeSetting.getVoteAndHeatRate()
//				.multiply(BigDecimal.valueOf(activeHelpRecord.getVoteCount()));
//
//			//原热力值+投票热力值
//			productUser.setHeatValue(BigDecimal.valueOf(heatValue.doubleValue()).add(productUser.getHeatValue())); //必须克隆对象，防止事务状态下，使用同一个对象地址
//
//			//添加热力值赠送记录=>赠送给参赛用户
//			HeatRecord heatRecord = new HeatRecord();
//			heatRecord.setActiveProductId(activeHelpRecord.getProductId());
//			heatRecord.setHeatValue(BigDecimal.valueOf(heatValue.doubleValue())); //必须克隆对象，防止事务状态下，使用同一个对象地址
//			heatRecord.setHeatType(HeatTypeEnum.HEAT_VALUE_SEND);
//			heatRecord.setUserId(productUser.getId());
//			Assert.isTrue(heatRecordService.save(heatRecord), "投票失败");
//			//修改活动热力值
//			activeProductRecord.setHeatValue(heatValue.add(activeProductRecord.getHeatValue()));
//			//放入ZSET缓存排名(缓存名:活动id,作品id,热力值)
//			Assert.isTrue(ActiveProductUtil.addProductRank(activeProductRecord), "投票失败");
//
//			//修改参赛用户选手信息
//			Assert.isTrue(loginUserService.updateById(productUser), "投票失败");
//		}
//	}

	/**
	 * 更新活动作品的票数和热力值
	 * @param activeHelpRecord
	 * @param activeProductRecord
	 * @param activeSetting
	 */
	@Override
	public void updateProductVoteAndHeat(ActiveHelpRecord activeHelpRecord, ActiveProductRecord activeProductRecord, ActiveSettingDto activeSetting) {
		//修改活动热力值和票数
		activeProductRecord.setVoteCount(activeProductRecord.getVoteCount() + 1);

		//判断是否赠送热力值
		if (ObjectUtils.isNotEmpty(activeSetting.getVoteAndHeatRate()) && !activeSetting.getVoteAndHeatRate().equals(BigDecimal.ZERO)) {
			//查询参赛用户
			UserHeat userHeat = userHeatService.getOne(Wrappers.<UserHeat>lambdaQuery().eq(UserHeat::getPhone, activeProductRecord.getPhone()));
			if(ObjectUtils.isEmpty(userHeat)){
				userHeat = new UserHeat();
				userHeat.setPhone(activeProductRecord.getPhone());
				userHeat.setHeatValue(BigDecimal.ZERO);
			}

			//热力值=活动票数*热力值比例
			BigDecimal heatValue = activeSetting.getVoteAndHeatRate()
				.multiply(BigDecimal.valueOf(activeHelpRecord.getVoteCount()));

			//原热力值+投票热力值
			userHeat.setHeatValue(BigDecimal.valueOf(heatValue.doubleValue()).add(userHeat.getHeatValue())); //必须克隆对象，防止事务状态下，使用同一个对象地址

			//添加热力值赠送记录=>赠送给参赛用户
			HeatRecord heatRecord = new HeatRecord();
			heatRecord.setActiveProductId(activeHelpRecord.getProductId());
			heatRecord.setHeatValue(BigDecimal.valueOf(heatValue.doubleValue())); //必须克隆对象，防止事务状态下，使用同一个对象地址
			heatRecord.setHeatType(HeatTypeEnum.HEAT_VALUE_SEND);
			heatRecord.setPhone(userHeat.getPhone());
			Assert.isTrue(heatRecordService.save(heatRecord), "投票失败");
			//修改活动热力值
			activeProductRecord.setHeatValue(heatValue.add(activeProductRecord.getHeatValue()));
			//放入ZSET缓存排名(缓存名:活动id,作品id,热力值)
			Assert.isTrue(ActiveProductUtil.addProductRank(activeProductRecord), "投票失败");

			//修改用户热力值信息
			Assert.isTrue(userHeatService.saveOrUpdate(userHeat), "投票失败");
		}
	}

//	/**
//	 * 更新用户普法积分
//	 * @param activeHelpRecord
//	 * @param loginUser
//	 * @param activeSetting
//	 */
//	@Override
//	public void userPuFaPointUpdate(ActiveHelpRecord activeHelpRecord, LoginUser loginUser, ActiveSettingDto activeSetting) {
//		//判断是否普法积分
//		if (ObjectUtils.isNotEmpty(activeSetting.getVoteAndPointRate()) && !activeSetting.getVoteAndPointRate().equals(BigDecimal.ZERO)) {
//			//修改普法积分(票数*积分比例+原有积分)
//			BigDecimal puFaPoint = activeSetting.getVoteAndPointRate()
//				.multiply(BigDecimal.valueOf(activeHelpRecord.getVoteCount()));
//			//添加普法积分赠送记录=>赠送给投票的用户
//			PointRecord pointRecord = new PointRecord();
//			pointRecord.setPoint(BigDecimal.valueOf(puFaPoint.doubleValue())); //必须克隆对象，防止事务状态下，使用同一个对象地址
//			pointRecord.setPointType(PointTypeEnum.PUFA_POINT_SEND);
//			pointRecord.setActiveProductId(activeHelpRecord.getProductId());
//			pointRecord.setUserId(activeHelpRecord.getUserId());
//			Assert.notNull(pointRecordService.save(pointRecord), "投票失败");
//			loginUser.setPufaPoint(puFaPoint.add(loginUser.getPufaPoint()));
//		}
//
//		//修改投票用户信息
//		Assert.isTrue(loginUserService.updateById(loginUser), "投票失败");
//	}

	/**
	 * 更新用户普法积分
	 * @param activeHelpRecord
	 * @param phone
	 * @param activeSetting
	 */
	@Override
	public void userPuFaPointUpdate(ActiveHelpRecord activeHelpRecord, String phone, ActiveSettingDto activeSetting) {
		//判断是否普法积分
		if (ObjectUtils.isNotEmpty(activeSetting.getVoteAndPointRate()) && !activeSetting.getVoteAndPointRate().equals(BigDecimal.ZERO)) {
			//修改普法积分(票数*积分比例+原有积分)
			BigDecimal puFaPoint = activeSetting.getVoteAndPointRate()
				.multiply(BigDecimal.valueOf(activeHelpRecord.getVoteCount()));
			//添加普法积分赠送记录=>赠送给投票的用户
			PointRecord pointRecord = new PointRecord();
			pointRecord.setPoint(BigDecimal.valueOf(puFaPoint.doubleValue())); //必须克隆对象，防止事务状态下，使用同一个对象地址
			pointRecord.setPointType(PointTypeEnum.PUFA_POINT_SEND);
			pointRecord.setActiveProductId(activeHelpRecord.getProductId());
			pointRecord.setUserId(activeHelpRecord.getUserId());
			Assert.notNull(pointRecordService.save(pointRecord), "投票失败");

			//修改积分
			UserPufaPoint userPufaPoint = userPufaPointService.getOne(Wrappers.<UserPufaPoint>lambdaQuery().eq(UserPufaPoint::getPhone, phone));
			if(ObjectUtils.isEmpty(userPufaPoint)){
				userPufaPoint = new UserPufaPoint();
				userPufaPoint.setPhone(phone);
				userPufaPoint.setHeatValue(BigDecimal.ZERO);
			}
			userPufaPoint.setHeatValue(userPufaPoint.getHeatValue().add(puFaPoint));

			//保存
			userPufaPointService.saveOrUpdate(userPufaPoint);
		}
	}

	/**
	 * 判断用户使用该道具对该活动助力次数是否到达上限
	 * @param activeHelpRecord
	 * @param activeProductRecord
	 * @param loginUser
	 * @param helpGoods
	 */
	@Override
	public void userHelpCountCheck(ActiveHelpRecord activeHelpRecord, ActiveProductRecord activeProductRecord, LoginUser loginUser, HelpGoods helpGoods) {
		//判断该用户对该活动助力是否达到上限(-1表示无上限)
		if (!Long.valueOf(-1).equals(helpGoods.getActiveVote())) {
			Map<String, Object> map = activeHelpRecordService.getMap(Wrappers.<ActiveHelpRecord>query().select(new StringBuilder("ifnull(sum(")
					.append(BeanPropertyUtil.getFieldNameToUnder(ActiveHelpRecord::getVoteCount))
					.append("),0) as count")
					.toString())
				.lambda()
				.eq(ActiveHelpRecord::getProductId, activeProductRecord.getId()) //判断作品ID
				.eq(ActiveHelpRecord::getUserId, loginUser.getId())    //判断用户ID
				.eq(ActiveHelpRecord::getHelpGoodsId, helpGoods.getId()) //判断道具ID
				.last(new StringBuilder("and date_format(")
					.append(BeanPropertyUtil.getFieldNameToUnder(PointRecord::getCreateTime))
					.append(",\"%Y-%m-%d\")=\"")
					.append(DateUtil.format(DateUtil.now(), "yyyy-MM-dd").trim()).append("\"").toString()));
			if ((MapUtil.getLong(map, "count") + activeHelpRecord.getVoteCount()) > helpGoods.getActiveVote()) {
				throw new HelpGoodsException("您今日使用该道具对该活动投票次数超过上限");
			}
		}
	}
}
