package com.cyksj.service.relation.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.BetweenFormater;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
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.common.util.StringUtil;
import com.cyksj.common.util.TicketCodeCommonUtil;
import com.cyksj.enums.GatewayApiCode;
import com.cyksj.mapper.*;
import com.cyksj.mapper.sys.SysEmailMapper;
import com.cyksj.model.entity.*;
import com.cyksj.model.request.SpecialGoodsTicketReq;
import com.cyksj.model.views.*;
import com.cyksj.redis.RedisService;
import com.cyksj.service.chatgpt.ChatGptAuthService;
import com.cyksj.service.groups.GroupsFuncService;
import com.cyksj.service.mail.CuiQiuMailService;
import com.cyksj.service.mail.MailService;
import com.cyksj.service.mange.coupon.CouponCommonService;
import com.cyksj.service.relation.GroupRelationFrontService;
import com.cyksj.service.user.UserBindRelationService;
import com.cyksj.service.user.UserLoginRecordService;
import com.ejlchina.searcher.BeanSearcher;
import com.ejlchina.searcher.SearchResult;
import com.ejlchina.searcher.param.Operator;
import com.ejlchina.searcher.util.MapBuilder;
import com.ejlchina.searcher.util.MapUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_ALREADY_BE_USER;
import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_NOT_FIND;

/*
 *项目名: netflix
 *文件名: GroupRelationFrontServiceImpl
 *创建者: JavaZou
 *创建时间:2022/12/29 15:42
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class GroupRelationFrontServiceImpl implements GroupRelationFrontService {
	private final UserBindRelationService userBindRelationService;

	private final UserMapper userMapper;

	private final BeanSearcher beanSearcher;

	private final CouponCommonService couponCommonService;

	private final GroupsRelationMapper groupsRelationMapper;

	private final GroupsMapper groupsMapper;

	private final ChatGptAuthService chatGptAuthService;

	private final RedisService redisService;

	private final MailService mailService;

	private final OrderDonMapper orderDonMapper;

	private final GroupsRelationExpiryNotifyRecordMapper groupsRelationExpiryNotifyRecordMapper;

	private final HttpServletRequest request;

	private final GroupsFuncService groupsFuncService;

	private final OrderDiscountPlusPurchaseSkuRelationMapper orderDiscountPlusPurchaseSkuRelationMapper;

	private final GroupsRelationLoginCodeRecordMapper groupsRelationLoginCodeRecordMapper;

	private final SysEmailMapper sysEmailMapper;

	private final GoodsDonSkuMapper goodsDonSkuMapper;

	private final UserFuncPropertyMapper userFuncPropertyMapper;

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

	private final UserLoginRecordService userLoginRecordService;

	private final CuiQiuMailService cuiQiuMailService;

	private final UserCertRecordMapper userCertRecordMapper;

	//脆球邮箱后缀
	private final static String CUI_QIU_EMAIL_SUFFIX = "@kindvd.com";
	private final UpgradePackageMapper upgradePackageMapper;

	private final static String VERIFY_CODE_SECRET = "q1w2e3";

	@Override
	public SearchResult<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize, String customId, String account) {
		User u = userMapper.selectById(userId);
		if (u == null) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
		if (u.getIsBlack()) {
			return new SearchResult<>();
		}
		List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, u);
		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
		//Long yhsId = yhShopFrontService.getYhsIdByCustomId(customId);
		DateTime now = DateTime.now();
		if (StrUtil.isNotBlank(account)) {
			builder.field(RenewalView::getAccount, account).op(Operator.Contain);
		}
		SearchResult<RenewalView> list = beanSearcher.search(RenewalView.class, builder
				.field(RenewalView::getUserId, 0).op(Operator.GreaterThan)
				.field(RenewalView::getUserId, userIds).op(Operator.InList)
				//.field(RenewalView::getYhsId, yhsId)
				.field("condition", String.format("(gr.expiry_time is null or gr.expiry_time > '%s')", now))
				.field(RenewalView::getStatus, List.of("validity", "overdue", "outside")).op(Operator.InList)
				.orderBy(RenewalView::getExpiryTime).asc()
				.build());
		//过滤邀请制、已失效的车位
		Integer size = list.getTotalCount().intValue();

		list.getDataList().forEach(ticket -> {
			if (ticket.getSkuId() == null || ticket.getGoodsId() == null) {
				return;
			}
			if (ticket.getGoodsId() == 18 && ticket.getSkuNum() > 1) {
				ticket.setPassword(null);
			}
			ticket.setIsMulti(false);
			if (ticket.getSkuNum() > 1) {
				ticket.setIsMulti(true);
			}
			//chatGPT直连
			if (ticket.getGoodsId().equals(42l)) {
				if (StrUtil.isNotBlank(ticket.getAccount())) {
					String accessToken;
					try {
						accessToken = chatGptAuthService.getAccessToken(ticket.getAccount());
						ticket.setGptRefreshToken(accessToken);
					} catch (Exception e) {
						redisService.set(RedisService.key.CHAT_GPT_TOKEN_EXCEPTION_KEY.getName() + ticket.getAccount(), ticket.getAccount());
					}
				}
				ticket.setAccount(null);
				ticket.setPassword(null);
			} else {
				ticket.setGptRefreshToken(null);
			}
			if (ticket.getSecondType() == 1) {
				ticket.setAccount(null);
				ticket.setPassword(null);
			}
			if (isLoginPopularize != null && isLoginPopularize) {
				GoodsDonViews views = beanSearcher.searchFirst(GoodsDonViews.class, MapUtils.builder().field(GoodsDonViews::getId, ticket.getGoodsId()).build());
				views.setSpecs(beanSearcher.searchFirst(GoodsDonSpecFrontView.class, MapUtils.builder().field(GoodsDonSpecFrontView::getGoodsId, views.getId()).build()));
				views.setSkuList(beanSearcher.searchAll(GoodsDonSkuFrontView.class, MapUtils.builder().field(GoodsDonSkuFrontView::getGoodsId, views.getId()).field(GoodsDonSkuFrontView::getStatus, true).build()));
				ticket.setGoodsDonViews(views);
			}
			if (ticket.getMonths() != null && ticket.getMonths() >= 300) {
				ticket.setExpiryTime(null);
			}
			if (ticket.getExpiryTime() != null && ticket.getGoodsType() == 1 && ticket.getSecondType() == 2) {
				String remainDays = DateUtil.formatBetween(now, ticket.getExpiryTime(), BetweenFormater.Level.DAY);
				if ("0天".equals(remainDays)) {
					remainDays = "小于1天";
				} else {
					//当天也算
					int days = Integer.parseInt(remainDays.substring(0, remainDays.indexOf("天")));
					remainDays = days + 1 + "天";
				}
				ticket.setRemainDays(remainDays);
			}
			OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
					.eq(OrderDon::getRelationId, ticket.getRelationId())
					.eq(OrderDon::getUserId, ticket.getUserId())
					.notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
					.orderByDesc(OrderDon::getId)
					.last("limit 1"));
			if (orderDon != null) {
				ticket.setOrderNo(orderDon.getOrderNo());
				ticket.setOrderId(orderDon.getId());
				ticket.setTransactionId(orderDon.getTransactionId());
			}

			if (size > 1 && ticket.getGoodsId() != 18) {
				Date payTime = null;
				if (orderDon != null) {
					payTime = Optional.ofNullable(orderDon.getPayTime()).orElse(orderDon.getCreatedTime());
				}
				//加购订单
				if (orderDon == null) {
					List<OrderDiscountPlusPurchaseSkuRelation> plusPurchaseSkuRelations = orderDiscountPlusPurchaseSkuRelationMapper.selectPlusRelationByIdAndUserId(ticket.getRelationId(), ticket.getUserId());
					for (OrderDiscountPlusPurchaseSkuRelation data : plusPurchaseSkuRelations) {
						String relationIds = data.getRelationIds();
						if (StrUtil.isEmpty(relationIds)) {
							return;
						}
						try {
							List<Long> relationList = Jsons.parseList(relationIds, Long.class);
							if (relationList.contains(ticket.getRelationId())) {
								OrderDon plusOrder = orderDonMapper.selectById(data.getOrderId());
								if (plusOrder != null) {
									payTime = Optional.ofNullable(plusOrder.getPayTime()).orElse(plusOrder.getCreatedTime());
								}
								break;
							}
						} catch (Exception e) {
						}

					}
				}
				ticket.setPayTime(payTime);
			}
			if (ticket.getGoodsId() == 26 && ticket.getIsMirror()){
				List<UpgradePackage> upgradePackages = upgradePackageMapper.selectList(Wrappers.lambdaQuery(UpgradePackage.class).eq(UpgradePackage::getSkuId, ticket.getSkuId()).eq(UpgradePackage::getStatus, Boolean.TRUE));
				if (CollectionUtil.isNotEmpty(upgradePackages)){
					upgradePackages.stream().map(e -> e.getPrice().divide(BigDecimal.valueOf(e.getNum()), 2, RoundingMode.HALF_UP)).min(BigDecimal::compareTo).ifPresent(ticket::setMjPackagePrice);
				}
			}
			List<GroupsRelationUserView> relationUserViews = groupsRelationMapper.getUserRelationUserViews(ticket.getGroupId(), ticket.getRelationId(), ticket.getUserId(), List.of(GroupsRelation.Status.validity, GroupsRelation.Status.outside));
			ticket.setRelationViews(relationUserViews);
			if (ticket.getExpiryTime() != null) {
				ticket.setExpiryTimeStr(DateUtil.format(ticket.getExpiryTime(), "yyyy-MM-dd"));
			}
			//查看双重验证码
			if (StrUtil.isNotEmpty(ticket.getApiSecret())) {
				Boolean isHasVerifyCode = StrUtil.isNotBlank(ticket.getVerifyCode()) ? true : false;
				Integer codeNum = getUserCodeNumBySkuId(ticket.getUserId(), ticket.getSkuId(), isHasVerifyCode);
				ticket.setCodeNum(codeNum);
			}
		});
		userLoginRecordService.saveUserLoginDayRecord(userId);
		return list;
	}

	@Override
	public Boolean isJoinCorpWx(Long userId, Boolean isJoin, Boolean noCoupon) {
		if (!isJoin) {
			User user = userMapper.selectById(userId);
			if (user == null || StrUtil.isEmpty(user.getUnionid())) {
				return true;
			}
//			CorpUser corpUser = corpUserMapper.selectOne(Wrappers.lambdaQuery(CorpUser.class)
//					.ne(CorpUser::getUnionid, "")
//					.eq(CorpUser::getUnionid, user.getUnionid())
//					.last("limit 1")
//					.select(CorpUser::getId)
//			);
			CorpUserFollowView corpUserFollowView = beanSearcher.searchFirst(CorpUserFollowView.class, MapUtils.builder()
					.field(CorpUserFollowView::getUnionId, user.getUnionid())
					.field(CorpUserFollowView::getStatus, 1).build());
			if (corpUserFollowView == null) {
				return false;
			}
		}
		//用户是否买了奈飞车票
		Number number = beanSearcher.searchCount(RenewalView.class, MapUtils.builder()
				.field(RenewalView::getUserId, userId)
				.field(RenewalView::getGoodsId, 1)
				.field(RenewalView::getStatus, List.of("validity", "overdue")).op(Operator.InList)
				.build());
		if (number.intValue() > 0 && !noCoupon) {
			couponCommonService.sendCouponToUser(userId, 34l, 0l, 0l, 0l, CouponUser.Channel.wxCorp);
		}
		return true;
	}

	@Override
	public GroupsRelation getSimilarExpiredGroupRelation(GoodsDonSku sku, List<Long> errorsRelationIds, String ip) {
		Long skuId = sku.getId();
		Integer days = sku.getDays();
		Integer months = sku.getMonths();
		Integer maxNum = sku.getNum();
		DateTime expiryTime = null;
		if (days != null && days > 0) {
			expiryTime = DateUtil.offsetDay(DateTime.now(), days);
		} else {
			expiryTime = DateUtil.offsetMonth(DateTime.now(), months);
		}
		Integer extraNum = 5;
		if (sku.getId() == 178l) {
			extraNum = 2;
		}
		maxNum += extraNum;
		DateTime minExpiryTime = DateUtil.offsetDay(expiryTime, -5);
		Long groupsId = groupsRelationMapper.selectSimilarExpiredRelation(skuId, minExpiryTime, maxNum, ip);
		if (groupsId == null) {
			log.info("暂无相似过期时间车队");
			return null;
		}
		GroupsRelation relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
				.notIn(errorsRelationIds != null && errorsRelationIds.size() > 0, GroupsRelation::getId, errorsRelationIds)
				.eq(GroupsRelation::getGroupsId, groupsId)
				.eq(GroupsRelation::getStatus, GroupsRelation.Status.none)
				.eq(GroupsRelation::getUserId, 0)
				.orderByAsc(GroupsRelation::getNum)
				.last("limit 1"));
		if (relation != null) {
			log.info("用户userId:{},获取相似车队的车位relationId:{}", relation.getId());
		}
		return relation;
	}

	@Override
	public Page<UserRecommendGoodsFrontView> getRecommendGoodsViews(Boolean isPayNf, List<Long> filter_goods_id, Integer start, Integer limit) {
		return groupsRelationMapper.getRecommendGoodsViews(new Page<>(start, limit),filter_goods_id, isPayNf);
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public void sendCourseWare(SpecialGoodsTicketReq request) throws Exception {
		Long userId = request.getUserId();
		Long relationId = request.getRelationId();
		String email = request.getEmail();
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		RenewalView relation = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder().field(RenewalView::getRelationId, relationId).build());
		Assert.notNull(relation, "您的车票不存在");
		Long relationUserId = relation.getUserId();
		if (!userIdList.contains(relationUserId)) {
			throw BusinessRuntimeException.getInstance("您的车票不存在");
		}
		if (relation.getSpecialType() != GoodsDon.SpecialType.courseware) {
			throw BusinessRuntimeException.getInstance("");
		}
		//是否已发送
		if (StrUtil.isNotBlank(relation.getGrAccount())) {
			throw BusinessRuntimeException.getInstance("已领取课件,请前往邮箱查看");
		}
		if (!Validator.isEmail(email)) {
			throw BusinessRuntimeException.getInstance("请输入正确的邮箱");
		}
		int update = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
				.set(GroupsRelation::getAccount, email)
				.and(qr -> qr.isNull(GroupsRelation::getAccount).or().eq(GroupsRelation::getAccount, StrUtil.EMPTY))
				.eq(GroupsRelation::getId, relationId));
		if (update > 0) {
			orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class)
					.set(OrderDon::getStatus, OrderDon.Status.complete)
					.eq(OrderDon::getRelationId, relationId)
					.eq(OrderDon::getUserId, userId)
					.eq(OrderDon::getStatus, OrderDon.Status.hasPayment));
			mailService.sendCoursewareByGoodsId(relation.getGoodsId(), relation.getRelationId(), relation.getUserId(), relation.getTitle(), email);
		}
	}

	@Override
	public GroupsRelation getRelation(Long payRelationId, Long userId, GoodsDonSku sku, String ip) {
		GroupsRelation relation = null;
		Integer maxNum = sku.getNum();
		if (payRelationId != null && payRelationId > 0) {
			relation = groupsRelationMapper.selectById(payRelationId);
			if (relation == null) {
				throw new BusinessRuntimeException(GROUP_INDEX_NOT_FIND.getCode(), GROUP_INDEX_NOT_FIND.getMsg());
			}
			if (relation.getUserId() != null && relation.getUserId() > 0L) {
				throw new BusinessRuntimeException(GROUP_INDEX_ALREADY_BE_USER.getCode(), GROUP_INDEX_ALREADY_BE_USER.getMsg());
			}

		} else {
			GroupsTrips groups = null;
			//ChatGpt Plus、Midjourney非独立规格 上车先获取硬塞座位 硬塞5个座位
			//主账号过期时间25天以外
			//23-12-06 MidJourney 不硬塞
			if (sku.getNum() > 1 && Constant.AI_goodsIds.get(0) == sku.getGoodsId()) {
				Integer extraNum = 5;
				if (sku.getId() == 178l || sku.getId() == 423l) {
					extraNum = 2;
				}
				maxNum += extraNum;
				DateTime time = DateUtil.offsetDay(DateUtil.beginOfDay(DateTime.now()), 25);
				//不塞存在该用户的车队
				Long groupsId = groupsRelationMapper.getOutSideGroupsTripsRelationByGoodsId(sku.getId(), time, extraNum, userId, sku.getNum(), maxNum);
				if (groupsId != null) {
					relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
							.eq(GroupsRelation::getGroupsId, groupsId)
							.eq(GroupsRelation::getUserId, 0)
							.eq(GroupsRelation::getStatus, GroupsRelation.Status.outside)
							.last("limit 1"));
					if (relation == null) {
						relation = new GroupsRelation();
						relation.setStatus(GroupsRelation.Status.outside);
						relation.setUserId(userId);
						relation.setGroupsId(groupsId);
						GroupsRelation maxNumRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsId).orderByDesc(GroupsRelation::getNum).last("limit 1"));
						Integer nextNum = maxNumRelation.getNum() + 1;
						if (redisService.setNx(RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getNameFormat(groupsId, nextNum), nextNum, RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getTimeout())) {
							relation.setNum(nextNum);
							groupsRelationMapper.insert(relation);
						} else {
							throw BusinessRuntimeException.getInstance("系统繁忙,请重试...");
						}
					}
					groups = groupsMapper.selectById(groupsId);
				}
			}
			if (groups == null) {
				//寻找差不多过期时间规格的车位
				relation = getSimilarExpiredGroupRelation(sku, null, ip);
				if (relation == null) {
					//TODO 如果没指定座位,等待逻辑确认
					groups = groupsMapper.selectTicketGroups(sku.getId(), GroupsTrips.Status.validity, maxNum, ip);

					if (groups == null) {
						//待发车
						groups = groupsMapper.selectTicketGroups(sku.getId(), GroupsTrips.Status.waiting, maxNum, ip);
					}
					//新增空车队
					if (groups == null) {
						relation = groupsFuncService.createNewGroupsTrips(sku);
					}
					//获取车位
					if (relation == null) {
						//寻找快满编车队进行占座
						relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId());
						if (relation == null) {
							Long groupsId = groups.getId();
							TASK_EXECUTOR.execute(() -> groupsMapper.updateAvailableNum(groupsId));
							throw BusinessRuntimeException.getInstance("系统繁忙,请重试...");
						}
					}
				}
			}
			if (groups == null) {
				groups = groupsMapper.selectById(relation.getGroupsId());
			}
			//车队目前可用停车数
			relation.setGroupsAvailParkingNum(groups.getAvailableParkingNum());
			relation.setMaxNum(maxNum);
		}
		return relation;
	}

	@Override
	public String getAiVerifyCode(Long userId, Long relationId, Integer type) throws Exception {
		List<Long> relationUserIdList = userBindRelationService.getRelationUserIdList(userId, null);
		RenewalView renewalView = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder().field(RenewalView::getUserId, relationUserIdList).op(Operator.InList)
				.field(RenewalView::getRelationId, relationId).build());
		if (renewalView == null) {
			throw BusinessRuntimeException.getInstance("您的车票不存在...");
		}
		if (StrUtil.isEmpty(renewalView.getAccount())) {
			throw BusinessRuntimeException.getInstance("车票未配置账号");
		}
		String account = renewalView.getAccount();
		String password = renewalView.getPassword();
		if (StrUtil.hasEmpty(account, password)) {
			throw BusinessRuntimeException.getInstance("您的车票账号密码异常,请联系客服...");
		}
		if (renewalView.getAccount().contains(CUI_QIU_EMAIL_SUFFIX)) {
			return cuiQiuMailService.getVerifyCode(renewalView.getAccount(), renewalView.getGoodsId());
		}
		//获取邮箱密码
		SysEmail sysEmail = sysEmailMapper.selectOne(Wrappers.lambdaQuery(SysEmail.class)
				.eq(SysEmail::getEmail, account)
				.last("limit 1"));
		if (sysEmail == null) {
			log.info("获取账号：{}验证码异常,未配置对应系统邮箱", account);
			throw BusinessRuntimeException.getInstance("获取账号验证码异常,请联系客服...");
		}
		String url = "http://yinhelx.com/api/controller.php";
		Map<String, Object> params = new HashMap<>();

		params.put("imap_key", "imap_56568niua@@");
		params.put("fun", "imap_read");
		params.put("imap_ip", "yinhelx.com");
		params.put("port", "143");
		params.put("username", account);
		params.put("password", sysEmail.getPassword());
		params.put("mbox_id", "0");
		params.put("delete", "0");

		HttpRequest post = HttpUtil.createPost(url);
		post.form(params);
		cn.hutool.http.HttpResponse execute = post.execute();
		if (execute.getStatus() != HttpStatus.HTTP_OK) {
			throw BusinessRuntimeException.getInstance("获取验证码异常,请联系客服...");
		}
		String code = getDifferentGoodsCode(renewalView.getGoodsId(), execute.body(), type);
		GroupsRelationLoginCodeRecord record = new GroupsRelationLoginCodeRecord();
		record.setUserId(userId);
		record.setRelationId(relationId);
		record.setAccount(renewalView.getAccount());
		record.setGoodsId(renewalView.getGoodsId());
		record.setSkuId(renewalView.getSkuId());
		groupsRelationLoginCodeRecordMapper.insert(record);
		return code;
	}


	@Override
	public void checkGroupsAvailParkingNum(Long skuId, Long groupsId, Integer availableParkingNum, Integer maxNum) {
		//GPT10人月付、4人月付
		if (skuId == 161l || skuId == 178l) {
			//为0时,不参与限制
			if (availableParkingNum == 0) {
				return;
			}
			//目前车队可用停车数
			//目前上车人数
			Integer currentParkingNum = groupsRelationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class)
					.eq(GroupsRelation::getGroupsId, groupsId)
					.ne(GroupsRelation::getUserId, 0)
					.le(GroupsRelation::getNum, maxNum));
			if (currentParkingNum > availableParkingNum) {
				throw BusinessRuntimeException.getInstance("系统繁忙,请重试...");
			}
		}
	}

	@Override
	public void adjustGroupsParkingTime(Long relationId, GoodsDonSku sku) {
		Long skuId = sku.getId();
		//更新GPT Plus10人、4人月付车队状态 待优化
		if (skuId == 161l || skuId == 178l || skuId == 422l || skuId == 423l) {
			GroupsRelation relation = groupsRelationMapper.selectById(relationId);
			Long groupsId = relation.getGroupsId();
			GroupsTrips groupsTrips = groupsMapper.selectById(groupsId);
			Integer availableParkingNum = groupsTrips.getAvailableParkingNum();
			//为0时 不参与限制
			if (availableParkingNum == 0) {
				return;
			}
			Integer extraNum = 5;
			if (skuId == 178l || skuId == 423l) {
				extraNum = 2;
			}
			Integer maxNum = sku.getNum() + extraNum;
			if (availableParkingNum >= maxNum) {
				return;
			}
			//目前上车人数
			Integer currentParkingNum = groupsRelationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class)
					.eq(GroupsRelation::getGroupsId, groupsId)
					.ne(GroupsRelation::getUserId, 0)
					.le(GroupsRelation::getNum, maxNum));
			if (currentParkingNum >= availableParkingNum) {
				//锁住
				DateTime parkingTime = DateUtil.offsetDay(DateTime.now(), 1);

				groupsMapper.update(null, Wrappers.lambdaUpdate(GroupsTrips.class)
						.eq(GroupsTrips::getId, groupsTrips.getId())
						.set(GroupsTrips::getParkingTime, parkingTime)
						.isNull(GroupsTrips::getParkingTime));
			}
		}
	}

	@Override
	public void setGroupsTripsParkingTimeEmpty(GoodsDonSku sku, Long relationId) {
		Long skuId = sku.getId();
		if (skuId == 161l || skuId == 178l) {
			GroupsRelation relation = groupsRelationMapper.selectById(relationId);
			Long groupsId = relation.getGroupsId();
			GroupsTrips groupsTrips = groupsMapper.selectById(groupsId);
			Integer availableParkingNum = groupsTrips.getAvailableParkingNum();
			if (groupsTrips.getParkingTime() == null || availableParkingNum == 0) {
				return;
			}
			Integer extraNum = 5;
			if (skuId == 178l) {
				extraNum = 2;
			}
			Integer skuNum = sku.getNum();
			if (availableParkingNum >= skuNum + extraNum) {
				return;
			}
			//目前上车人数
			Integer currentParkingNum = groupsRelationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class)
					.eq(GroupsRelation::getGroupsId, groupsId)
					.ne(GroupsRelation::getUserId, 0));
			if (currentParkingNum < availableParkingNum) {

				groupsMapper.update(null, Wrappers.lambdaUpdate(GroupsTrips.class)
						.eq(GroupsTrips::getId, groupsTrips.getId())
						.set(GroupsTrips::getParkingTime, null)
						.isNotNull(GroupsTrips::getParkingTime));
			}
		}
	}

	@Override
	public Integer getUserCodeNumBySkuId(Long userId, Long skuId, Boolean isHasVerifyCode) {
		//查看双重验证码
		UserFuncProperty userFuncProperty = userFuncPropertyMapper.selectOne(Wrappers.lambdaQuery(UserFuncProperty.class).eq(UserFuncProperty::getUserId, userId).last("limit 1"));
		//默认2次
		int num = 2;
		//有安全码查看次数 置为0
		if (isHasVerifyCode) {
			num = 0;
			//存在身份实名认证有两次机会
			List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
			Integer selectCount = userCertRecordMapper.selectCount(Wrappers.lambdaQuery(UserCertRecord.class)
					.in(UserCertRecord::getUserId, userIdList));
			if (selectCount > 0) {
				num = 2;
			}
			return num;
		}
		//查看双重验证码次数
		GoodsDonSku sku = goodsDonSkuMapper.selectById(skuId);
		if (sku.getCodeNum() > 0) {
			num = sku.getCodeNum();
		}
		if (userFuncProperty != null) num = userFuncProperty.getVerifyCheckNum();
		return num;
	}

	@Override
	public List<RenewalView> getHasPayGoods(long userId) {
		User user = userMapper.selectById(userId);
		List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, user);
		DateTime now = DateTime.now();
		List<RenewalView> list = groupsRelationMapper.getUserHasPayGoods(userIds, now);
		return list;
	}

	@Override
	public List<RenewalView> getExpiryRenewalNotify(Long userId) {
		DateTime now = DateTime.now();
		DateTime thisZero = DateUtil.beginOfDay(now);
		String thisDate = thisZero.toDateStr();
		Object exists = redisService.get(RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getNameFormat(thisDate, userId));
		if (exists != null) {
			return null;
		}
		User u = userMapper.selectById(userId);
		if (u == null) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
		if (u.getIsBlack()) {
			redisService.setNx(RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getNameFormat(thisDate, userId), userId, RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getTimeout());
			return null;
		}
		List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, u);
		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
		List<RenewalView> list = beanSearcher.searchAll(RenewalView.class, builder
				.field(RenewalView::getUserId, 0).op(Operator.GreaterThan)
				.field(RenewalView::getUserId, userIds).op(Operator.InList)
				.field(RenewalView::getExpiryTime, now).op(Operator.GreaterThan)
				.field(RenewalView::getStatus, List.of("validity", "overdue", "outside")).op(Operator.InList)
				.orderBy(RenewalView::getExpiryTime).asc()
				.onlySelect(RenewalView::getMonths, RenewalView::getExpiryTime, RenewalView::getRelationId, RenewalView::getAccount, RenewalView::getGoodsId, RenewalView::getTitle, RenewalView::getLogo, RenewalView::getImg, RenewalView::getGroupId, RenewalView::getSkuId, RenewalView::getSpecVal, RenewalView::getGoodsStatus, RenewalView::getSkuStatus)
				.build());
		if (list.size() > 5) {
			redisService.setNx(RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getNameFormat(thisDate, userId), userId, RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getTimeout());
			return null;
		}
		//提前7天
		AtomicInteger day = new AtomicInteger(7);
		List<RenewalView> expiryTickets = list.stream().filter(ticket -> {
			//下架
			if (ticket.getGoodsStatus() == null || ticket.getSkuStatus() == null || !ticket.getGoodsStatus() || !ticket.getSkuStatus()) {
				return false;
			}
			Integer skuMonths = ticket.getMonths();
			Date expiryTime = ticket.getExpiryTime();
			//年付 提前一个月
			if (skuMonths >= 12) {
				day.set(30);
			} else {
				day.set(7);
			}
			if (DateUtil.beginOfDay(expiryTime).compareTo(DateUtil.offsetDay(thisZero, day.get())) <= 0) {
				ticket.setExpiryTimeStr(DateUtil.format(ticket.getExpiryTime(), "yyyy-MM-dd"));
				ticket.setExpiryTime(null);
				return true;
			}
			return false;
		}).collect(Collectors.toList());
		redisService.setNx(RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getNameFormat(thisDate, userId), userId, RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getTimeout());
		if (CollUtil.isNotEmpty(expiryTickets)) {
			groupsRelationExpiryNotifyRecordMapper.batchInsert(userId, expiryTickets);
		}
		return expiryTickets;
	}

	public String getDifferentGoodsCode(Long goodsId, String body, Integer type) {
		String code = null;
		//奈飞
		if (goodsId == 1) {
			if (body.contains("輸入此代碼登入")) {
				code = StrUtil.subBetween(body, "輸入此代碼登入", "請在裝置上輸入上");
			} else {
				String urlPref = "https://www.netflix.com/account/update-primary-location";
				code = StrUtil.subBetween(body, "[" + urlPref, "]");
				if (StrUtil.isEmpty(code)) {
					urlPref = "https://www.netflix.com/account/travel/verify";
					code = StrUtil.subBetween(body, "[" + urlPref, "]");
					if (StrUtil.isEmpty(code) && type == null) {
						throw BusinessRuntimeException.getInstance("获取认证链接失败,请重新获取");
					}
				}
				if (StrUtil.isNotBlank(code)) {
					return urlPref + code;
				}
			}
			if (type != null && type == 1) {
				throw BusinessRuntimeException.getInstance("查询失败，请检查是否发送了登陆码..");
			}
		}
		if (StrUtil.isEmpty(code)) {
			code = TicketCodeCommonUtil.getTicketCodeStr(body, goodsId);
		}
		int length = 4;
		if (goodsId == 33l) {
			length = 6;
		}
		code = StringUtil.getVerifyCodePattern(code, length);
		if (!Validator.isNumber(code)) {
			log.error("获取账号验证码失败:{}", StrUtil.subSufByLength(code, 512));
			throw BusinessRuntimeException.getInstance("获取验证码失败,请重新获取..");
		}
		return code.trim();
	}
}
