package com.cyksj.service.coupon.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
import com.cyksj.common.util.Jsons;
import com.cyksj.enums.GatewayApiCode;
import com.cyksj.mapper.OrderDonMapper;
import com.cyksj.mapper.UserMapper;
import com.cyksj.mapper.channel.ChannelPopularizeMapper;
import com.cyksj.mapper.manage.coupon.*;
import com.cyksj.model.entity.*;
import com.cyksj.model.request.ChannelPopularizeCouponReq;
import com.cyksj.model.request.CouponCollectReq;
import com.cyksj.model.views.*;
import com.cyksj.service.coupon.CouponFontService;
import com.ejlchina.searcher.BeanSearcher;
import com.ejlchina.searcher.param.Operator;
import com.ejlchina.searcher.util.MapUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/*
 *项目名: netflix
 *文件名: CouponFontServiceImpl
 *创建者: JavaZou
 *创建时间:2022/11/18 13:34
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CouponFontServiceImpl implements CouponFontService {
	private final CouponMapper couponMapper;

	private final CouponActiveMapper couponActiveMapper;

	private final CouponUserMapper couponUserMapper;

	private final BeanSearcher beanSearcher;

	private final CouponSkuMapper couponSkuMapper;

	private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();

	private final CouponRecommendMapper recommendMapper;

	private final ChannelPopularizeMapper channelPopularizeMapper;

	private final UserMapper userMapper;

	private final OrderDonMapper orderDonMapper;

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public void collectCoupon(CouponCollectReq couponCollectReq, Long userId) {
		collectCommonCheck(couponCollectReq.getCouponId(), userId);
		CouponActive couponActive = couponActiveMapper.selectById(couponCollectReq.getCouponActiveId());
		if (couponActive == null) {
			throw BusinessRuntimeException.getInstance("该发放优惠券不存在");
		}
		if (couponActive.getRemainNum() <= 0) {
			throw BusinessRuntimeException.getInstance("该优惠券已领取完");
		}

		receiveCouponUser(couponCollectReq.getCouponId(), userId, CouponUser.Channel.center);
		if (couponActive != null) {
			//发放优惠券记录剩余数量
			Integer remainNum = couponActive.getRemainNum();
			Integer update = couponActiveMapper.subRemainNum(couponActive.getId(), remainNum);
			if (update != 1) {
				throw BusinessRuntimeException.getInstance("系统繁忙,请稍后再试..");
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public void collectRecommendCoupon(CouponCollectReq couponCollectReq, Long userId) {
		collectCommonCheck(couponCollectReq.getCouponId(), userId);
		CouponRecommend couponRecommend = recommendMapper.selectOne(Wrappers.lambdaQuery(CouponRecommend.class).eq(CouponRecommend::getCouponId, couponCollectReq.getCouponId()).last("limit 1"));
		if (couponRecommend == null || !couponRecommend.getDeleted() || !couponRecommend.getStatus()) {
			return;
		}
		Date upTime = couponRecommend.getUpTime();
		Date downTime = couponRecommend.getDownTime();
		if (upTime != null && upTime.after(DateTime.now())) {
			return;
		}
		if (downTime != null && downTime.before(DateTime.now())) {
			return;
		}
		receiveCouponUser(couponCollectReq.getCouponId(), userId, CouponUser.Channel.recommend);
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public void collectWholeRecommendCoupon(Long userId) {
		CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
		Boolean isNewUser = true;
		if (couponNewUserView != null) {
			isNewUser = false;
		}
		//查询所有可领取的推荐优惠券
		List<CouponAvailableRecommendView> couponAvailableRecommendViews = recommendMapper.getRecommendCouponList(userId, isNewUser);
		couponAvailableRecommendViews.stream().forEach(data -> {
			//领取优惠券
			CouponUser couponUser = new CouponUser();
			couponUser.setUserId(userId);
			couponUser.setCouponId(data.getCouponId());
			//推荐渠道
			couponUser.setChannel(CouponUser.Channel.recommend);
			couponUser.setStatus(CouponUser.Status.unused);
			couponUser.setRecommendId(data.getRecommendId());
			//优惠券有效时间
			this.updateCouponUserValidTime(data.getCouponId(), couponUser);
			try {
				couponUserMapper.insert(couponUser);
			} catch (DuplicateKeyException e) {
				//插入失败继续插入 不影响
				log.info("用户:{}一键领取推荐优惠券{}插入数据错误", userId, data.getCouponId());
			}
		});
	}

	@Override
	public Page<CouponUserView> getAvailableCouponList(Long skuId, Long couponId, Long userId, Boolean isRenew, Long start, Long limit) {
		DateTime now = DateTime.now();
		Long goodsId = null;
		//实物还是虚物
		GoodsDonSkuView goodsDonSkuView = beanSearcher.searchFirst(GoodsDonSkuView.class, MapUtils.builder().field(GoodsDonSkuView::getSkuId, skuId).op(Operator.Equal).build());
		if (goodsDonSkuView == null) {
			return new Page<>();
		}
		BigDecimal skuMoney = goodsDonSkuView.getMoney();
		if (goodsDonSkuView.getType() == 2) {
			goodsId = goodsDonSkuView.getGoodsId();
		}
		Page<CouponUserView> availableCouponList = couponUserMapper.getAvailableCouponList(skuId, skuMoney, couponId, goodsId, userId, isRenew, new Page<>(start, limit));
		Optional.ofNullable(availableCouponList).ifPresent(page->{
			page.getRecords().stream().forEach(data->{
				String str = couponSkuMapper.selectGoodsSkuStr(data.getCouponId());
				data.setGoodsSkuStr(str.replaceAll(",", "/").replaceAll(";", ""));
				List<CouponSkuView> couponSkus = couponSkuMapper.getGoodsSkuByCouponId(data.getCouponId());
				try {
					data.setGoodsSkuIds(Jsons.toJson(couponSkus));
				} catch (Exception e) {

				}

				if (!data.getIsAvailable()) {
					data.setReason(String.format("仅限%s", data.getGoodsSkuStr()));
					if (data.getUseScope() == Coupon.UseScope.renew) {
						data.setReason(String.format("%s续费时可使用", data.getReason()));
					} else if (data.getUseScope() == Coupon.UseScope.orders) {
						data.setReason(String.format("%s下单时可使用", data.getReason()));
					}
				}

				if (goodsDonSkuView.getType() == 2 && data.getType() == Coupon.Type.reduce) {
					if (data.getIsAvailable() && skuMoney.compareTo(data.getReduceCondition()) < 0) {
						data.setIsAvailable(false);
						data.setReason(String.format("满%s可用", data.getReduceCondition().divide(BigDecimal.valueOf(100))));
					}
				}

				if (isRenew != null && isRenew && data.getUseScope() == Coupon.UseScope.orders) {
					data.setReason("仅下单可使用");
				}
				//为了重新校验
				data.setCouponUserStatus(CouponUser.Status.unused);
				this.setCouponUserStatus(data, now);
			});
		});
		if (goodsDonSkuView.getType() == 2) {
			availableCouponList.getRecords().sort(Comparator.comparing(CouponUserView::getIsAvailable).reversed());
		}
		return availableCouponList;
	}

	/**
	 * 设置用户优惠券状态
	 */
	@Override
	public void setCouponUserStatus(CouponUserView data, DateTime now) {
		Boolean isFlag = false;
		if (data.getCouponUserStatus() == CouponUser.Status.unused) {
			if (data.getExpiryStatus() != null && !data.getExpiryStatus()) {
				data.setCouponUserStatus(CouponUser.Status.invalid);
				data.setIsAvailable(false);
				data.setReason("该优惠券已失效");
				isFlag = true;
			} else if (now.isAfter(data.getValidEndTime())) {
				data.setCouponUserStatus(CouponUser.Status.expired);
				data.setIsAvailable(false);
				data.setReason("该优惠券已过期");
				isFlag = true;
			} else if (now.isBefore(data.getValidStartTime())) {
				data.setCouponUserStatus(CouponUser.Status.notEffective);
				data.setIsAvailable(false);
				data.setReason("该优惠券未生效");
				isFlag = true;
			}
		}
		if (isFlag) {
			TASK_EXECUTOR.execute(() -> {
				if (data.getCouponUserStatus() != CouponUser.Status.notEffective) {
					CouponUser couponUser = new CouponUser();
					couponUser.setId(data.getId());
					couponUser.setStatus(data.getCouponUserStatus());
					couponUserMapper.updateById(couponUser);
				}
			});
		}
	}

	@Override
	public Integer collectRecommendCouponNum(Long userId, Boolean isNewUser) {
		List<CouponAvailableRecommendView> recommendCouponList = Optional.ofNullable(recommendMapper.getRecommendCouponList(userId, isNewUser)).orElse(new ArrayList<>());
		return recommendCouponList.size();
	}

	public void collectCommonCheck(Long couponId, Long userId) {
		Coupon coupon = couponMapper.selectById(couponId);
		if (coupon == null || !coupon.getDeleted()) {
			throw BusinessRuntimeException.getInstance("该优惠券不存在");
		}
		//是否可领取
		if (coupon.getScope() == Coupon.Scope.newUser) {
			//注册后从没产生过虚拟订单的用户，产生过退款后也不是新用户
			CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
			if (couponNewUserView != null) {
				throw BusinessRuntimeException.getInstance("该优惠券只能新用户才能领取");
			}
		}
		CouponUser couponUser = couponUserMapper.selectOne(Wrappers.lambdaQuery(CouponUser.class).eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, couponId));
		if (couponUser != null) {
			if (couponUser.getChannel() == CouponUser.Channel.exCode) {
				throw BusinessRuntimeException.getInstance("您已兑换过该优惠券..");
			}
			throw BusinessRuntimeException.getInstance("您已领取该优惠券..");
		}
	}

	@Override
	public void updateCouponUserValidTime(Long couponId, CouponUser couponUser) {
		Coupon entity = couponMapper.getCouponById(couponId);
		Optional.ofNullable(entity).ifPresent(coupon -> {
			if (coupon.getIsValidTime()) {
				couponUser.setValidStartTime(coupon.getValidStartTime());
				couponUser.setValidEndTime(coupon.getValidEndTime());
				return;
			}
			couponUser.setValidStartTime(DateTime.now());
			if (coupon.getValidHours() > 0) {
				couponUser.setValidEndTime(DateUtil.offsetHour(couponUser.getValidStartTime(), coupon.getValidHours()));
				return;
			}
			couponUser.setValidEndTime(DateUtil.offsetDay(couponUser.getValidStartTime(), coupon.getValidDays()));
		});
	}

	@Override
	public void updateOrderDonCouponStatus(OrderDon orderDon) {
		log.info("订单:{}退款,优惠券返还start...", orderDon.getId());
		CouponUser couponUser = couponUserMapper.selectById(orderDon.getCouponUserId());
		if (CouponUser.Channel.exCode == couponUser.getChannel()) {
			//兑换码兑换的优惠券退款时，直接删除
			couponUserMapper.deleteById(couponUser.getId());
		} else {
			CouponUserView couponUserView = beanSearcher.searchFirst(CouponUserView.class, MapUtils.builder()
					.field(CouponUserView::getCouponId, couponUser.getCouponId()).op(Operator.Equal)
					.field(CouponUserView::getUserId, orderDon.getUserId()).op(Operator.Equal)
					.build());
			couponUserView.setCouponUserStatus(CouponUser.Status.unused);
			this.setCouponUserStatus(couponUserView, DateTime.now());
			couponUser.setStatus(couponUserView.getCouponUserStatus());
			couponUserMapper.updateById(couponUser);
		}
		log.info("订单:{}退款,优惠券返还end...", orderDon.getId());
	}

	@Override
	public void receiveChannelPopularizeCoupon(ChannelPopularizeCouponReq req) {
		Long userId = req.getUserId();
		Long popularizeId = req.getPopularizeId();
		Long couponId = req.getCouponId();
		ChannelPopularize channelPopularize = checkPopularizeChannelCoupon(userId, popularizeId);
		String couponIds = channelPopularize.getCouponIds();
		List<Long> couponIdList = null;
		try {
			couponIdList = Jsons.parseList(couponIds, Long.class);
			if (!couponIdList.contains(couponId)) {
				throw BusinessRuntimeException.getInstance("链接未关联该优惠券");
			}
		} catch (Exception e) {
			throw BusinessRuntimeException.getInstance("链接未关联该优惠券");
		}
		//优惠券领取状态校验
		collectCommonCheck(couponId, userId);
		//领取优惠券
		receiveCouponUser(couponId, userId, CouponUser.Channel.channel_popularize);
	}

	@Override
	public void collectAllChannelCoupons(long userId, Long popularizeId) {
		ChannelPopularize channelPopularize = checkPopularizeChannelCoupon(userId, popularizeId);
		String couponIds = channelPopularize.getCouponIds();
		List<Long> couponIdList = null;
		try {
			couponIdList = Jsons.parseList(couponIds, Long.class);
		} catch (Exception e) {
			throw BusinessRuntimeException.getInstance("链接未关联优惠券");
		}
		//一键领取优惠券
		couponIdList.forEach(couponId -> {
			try {
				receiveCouponUser(couponId, userId, CouponUser.Channel.channel_popularize);
			} catch (Exception e) {
			}
		});
	}

	public ChannelPopularize checkPopularizeChannelCoupon(Long userId, Long popularizeId) {
		//是否是该渠道来源新用户
		User user = userMapper.selectById(userId);
		if (user == null) {
			throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_USER_NO_FIND);
		}
		if (!user.getPopularizeId().equals(popularizeId)) {
			throw BusinessRuntimeException.getInstance("渠道推广新用户才能领取该优惠券");
		}
		//渠道链接是否存在
		ChannelPopularize channelPopularize = channelPopularizeMapper.selectById(popularizeId);
		Assert.notNull(channelPopularize, "链接不存在");
		//是否关联该优惠券
		String couponIds = channelPopularize.getCouponIds();
		if (StrUtil.isEmpty(couponIds)) {
			throw BusinessRuntimeException.getInstance("链接未关联优惠券");
		}
		return channelPopularize;
	}

	/**
	 * 领取优惠券
	 */
	public void receiveCouponUser(Long couponId, Long userId, CouponUser.Channel channel) {
		CouponUser couponUser = new CouponUser();
		couponUser.setUserId(userId);
		couponUser.setCouponId(couponId);

		couponUser.setChannel(channel);
		couponUser.setStatus(CouponUser.Status.unused);
		//优惠券有效时间
		this.updateCouponUserValidTime(couponId, couponUser);
		try {
			couponUserMapper.insert(couponUser);
		} catch (DuplicateKeyException e) {
			log.info("用户:{}重复领取优惠券{}插入数据错误", userId, couponId);
		}
	}

	@Override
	public CouponUserView getNewUserWelfareCoupons(long userId,Long couponId) {
		return couponUserMapper.getNewUserWelfareCouponsByUserId(userId, couponId);
	}

	@Override
	public CouponUserView getCouponDetailById(long userId, Long couponId) {
		CouponUserView couponUserView = couponUserMapper.getCouponDetailById(userId, couponId);
		if (couponUserView != null) {
			String str = couponSkuMapper.selectGoodsSkuStr(couponUserView.getCouponId());
			couponUserView.setGoodsSkuStr(str.replaceAll(",", "/").replaceAll(";", ""));
		}
		return couponUserView;
	}

	@Override
	public CouponUserView receiveCoupon(long userId, Long couponId, CouponUser.Channel channel) {
		try {
			receiveCouponUser(couponId, userId, channel);
		} catch (Exception e) {
			return null;
		}
		return getCouponDetailById(userId, couponId);
	}

	@Override
	public List<CouponView> getGoodsUserActivityCoupons(long userId) throws Exception {
		UserActivityDistributeDetailView goodsActivity = getGoodsActivity();
		if (goodsActivity == null) {
			return null;
		}
		String couponIds = goodsActivity.getCouponIds();
		List<Long> couponIdList = Jsons.parseList(couponIds, Long.class);
		//是否领取过
		Integer selectCount = couponUserMapper.selectCount(Wrappers.lambdaQuery(CouponUser.class).in(CouponUser::getCouponId, couponIdList).eq(CouponUser::getUserId, userId));
		if (selectCount == couponIdList.size()) {
			return null;
		}
		//未领取
		//是否购买过
		List<Long> skuIdList = couponMapper.getCouponSkuIds(couponIdList);
		Integer orderCount = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).notIn(OrderDon::getStatus, Constant.noOrderAllStatus).in(OrderDon::getSkuId, skuIdList));
		if (orderCount == 0) {
			return null;
		}
		List<CouponView> couponViews = beanSearcher.searchAll(CouponView.class, MapUtils.builder().field(CouponView::getCouponId, couponIdList).op(Operator.InList).orderBy(CouponView::getCouponId).build());
		return couponViews;
	}

	@Override
	public void collectAllGoodsActivityCoupons(long userId) throws Exception {
		UserActivityDistributeDetailView goodsActivity = getGoodsActivity();
		if (goodsActivity != null) {
			String couponIds = goodsActivity.getCouponIds();
			List<Long> couponIdList = Jsons.parseList(couponIds, Long.class);
			//是否领取过
			Integer selectCount = couponUserMapper.selectCount(Wrappers.lambdaQuery(CouponUser.class).in(CouponUser::getCouponId, couponIdList).eq(CouponUser::getUserId, userId));
			if (selectCount != couponIdList.size()) {
				//未领取
				//是否购买过
				List<Long> skuIdList = couponMapper.getCouponSkuIds(couponIdList);
				Integer orderCount = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).notIn(OrderDon::getStatus, Constant.noOrderAllStatus).in(OrderDon::getSkuId, skuIdList));
				if (orderCount != 0) {
					//一键领取优惠券
					couponIdList.forEach(couponId -> {
						try {
							receiveCouponUser(couponId, userId, CouponUser.Channel.ptfq);
						} catch (Exception e) {
						}
					});
				}
			}
		}
	}

	public UserActivityDistributeDetailView getGoodsActivity() {
		String dateStr = DateTime.now().toString();
		String time = String.format(" and (ua.start_time is null or (ua.start_time < '%s' and ua.end_time > '%s'))", dateStr, dateStr);
		UserActivityDistributeDetailView goodsActivity = beanSearcher.searchFirst(UserActivityDistributeDetailView.class, MapUtils.builder()
				.field(UserActivityDistributeDetailView::getType, 3)
				.put("time", time)
				.build());
		return goodsActivity;
	}
}
