package com.cyksj.service.codex.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.snowflake.Sequence;
import com.cyksj.common.util.Jsons;
import com.cyksj.common.util.StringUtil;
import com.cyksj.dto.RedisKey;
import com.cyksj.mapper.*;
import com.cyksj.mapper.codex.CodexDeductRecordMapper;
import com.cyksj.mapper.codex.CodexUserRenewExpiryRecordMapper;
import com.cyksj.mapper.manage.coupon.CouponMapper;
import com.cyksj.mapper.manage.coupon.CouponSkuMapper;
import com.cyksj.mapper.manage.coupon.CouponUserMapper;
import com.cyksj.mapper.manage.distribute.UserDistributeMapper;
import com.cyksj.mapper.manage.distribute.UserDistributeSharedMapper;
import com.cyksj.model.dto.CouponPopularizeDto;
import com.cyksj.model.entity.*;
import com.cyksj.model.manage.views.GroupsRelationView;
import com.cyksj.model.request.CodexUpgradePayReq;
import com.cyksj.model.request.UpdateDailyLimitRequest;
import com.cyksj.model.request.codex.CodexUserPackageReq;
import com.cyksj.model.response.CodexDeductResp;
import com.cyksj.model.response.claudecode.ClaudeCodeResp;
import com.cyksj.model.views.CodexUserInfoView;
import com.cyksj.model.views.CouponNewUserView;
import com.cyksj.model.views.CouponUserView;
import com.cyksj.redis.RedisService;
import com.cyksj.service.codex.CodexService;
import com.cyksj.service.coupon.CouponFontService;
import com.cyksj.service.groups.GroupsFuncService;
import com.cyksj.service.user.UserBindRelationService;
import com.ejlchina.searcher.BeanSearcher;
import com.ejlchina.searcher.param.Operator;
import com.ejlchina.searcher.util.MapBuilder;
import com.ejlchina.searcher.util.MapUtils;
import com.github.rholder.retry.*;
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.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 项目名: yhlxj11111111
 * 文件名: CodexServiceImpl
 * 创建者: Claude
 * 创建时间:2025/9/15
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CodexServiceImpl implements CodexService {

	private final CodexUserMapper codexUserMapper;

	private final ClaudeCodeUserMapper claudeCodeUserMapper;

	private final UserBindRelationService userBindRelationService;

	private final GoodsDonSkuMapper skuMapper;

	private final GoodsDonMapper goodsDonMapper;

	private final CouponMapper couponMapper;

	private final GroupsRelationMapper relationMapper;

	private final GroupsMapper groupsMapper;

	private final CodexUserRenewExpiryRecordMapper codexUserRenewExpiryRecordMapper;

	private final BeanSearcher beanSearcher;

	private final OrderDonMapper orderDonMapper;

	private final GroupsFuncService groupsFuncService;

	private final RedisService redisService;

	private final CodexDeductRecordMapper codexDeductRecordMapper;

	private final CouponSkuMapper couponSkuMapper;

	private final CouponUserMapper couponUserMapper;

	private final UserDistributeMapper userDistributeMapper;

	private final UserDistributeSharedMapper userDistributeSharedMapper;

	private final UserMapper userMapper;

	private final CouponFontService couponFontService;

	private static final Sequence SEQUENCE = new Sequence(0);
	@Override
	public CodexUserInfoView getCodexUserInfo(Long userId) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
		// 查询Claude Code信息
		CodexUserInfoView.ClaudeCodeInfo claudeCodeInfo = getClaudeCodeInfo(userId);

		if (codexUser == null) {
			//是否有claude code
			if (claudeCodeInfo != null && claudeCodeInfo.getClaudeDailyLimit() != null) {
				GoodsDonSku sku = null;
				if (claudeCodeInfo.getRenewSkuId() != null) {
					sku = skuMapper.selectById(claudeCodeInfo.getRenewSkuId());
				}
				//续费升级规格不存在 或者 不赠送codex
				if (sku == null || !sku.getIsCodex()) {
					GroupsRelation relation = relationMapper.selectById(claudeCodeInfo.getRelationId());
					GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
					sku = skuMapper.selectById(groupsTrips.getSkuId());
				}

				//sku 存在并且开启赠送codex
				if (sku != null && sku.getIsCodex()) {
					CodexUserPackageReq codexPackageReq = CodexUserPackageReq.builder()
							.userId(claudeCodeInfo.getUserId())
							.planName(sku.getCodexPlanName())
							.openaiDailyLimit(sku.getOpenaiDailyLimit())
							.openaiQuota(sku.getOpenaiQuota())
							.expiryTime(claudeCodeInfo.getExpiryTime())
							.build();
					createOrUpdateUserPackage(codexPackageReq);
					codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
				}
			}
			if (codexUser == null) {
				return null;
			}
		}


		return CodexUserInfoView.builder().planName(codexUser.getPlanName()).openaiDailyLimit(codexUser.getOpenaiDailyLimit()).openaiQuota(codexUser.getOpenaiQuota()).relationId(codexUser.getRelationId()).claudeCodeInfo(claudeCodeInfo).build();
	}

	private CodexUserInfoView.ClaudeCodeInfo getClaudeCodeInfo(Long userId) {
		// 获取用户关联的ID列表
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);

		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));

		if (claudeCodeUser == null) {
			return null;
		}

		return CodexUserInfoView.ClaudeCodeInfo.builder()
				.userId(claudeCodeUser.getUserId())
				.planName(claudeCodeUser.getPlanName())
				.relationId(claudeCodeUser.getRelationId())
				.claudeDailyLimit(claudeCodeUser.getClaudeDailyLimit())
				.claudeQuota(claudeCodeUser.getClaudeQuota())
				.expiryTime(claudeCodeUser.getExpiryTime())
				.renewSkuId(claudeCodeUser.getRenewSkuId())
				.renewExpiryTime(claudeCodeUser.getRenewExpiryTime()).build();
	}

	@Override
	public void createOrUpdateUserPackage(CodexUserPackageReq req) {
		Long userId = req.getUserId();
		// 构建完整的套餐参数
		String planName = req.getPlanName();
		Date expiryTime = req.getExpiryTime();
		Integer openaiDailyLimit = req.getOpenaiDailyLimit();
		Integer openaiQuota = req.getOpenaiQuota();
		Long relationId = req.getRelationId();
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		CodexUser existingCodexUser = Optional.ofNullable(codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"))).orElse(new CodexUser());

		existingCodexUser.setPlanName(planName);
		existingCodexUser.setRelationId(relationId);
		existingCodexUser.setUserId(userId);
		existingCodexUser.setOpenaiDailyLimit(openaiDailyLimit);
		existingCodexUser.setOpenaiQuota(openaiQuota);
		existingCodexUser.setExpiryTime(expiryTime);

		if (existingCodexUser.getId() == null) {
			try {
				codexUserMapper.insert(existingCodexUser);
			} catch (DuplicateKeyException e) {

			}
			return;
		}
		codexUserMapper.updateById(existingCodexUser);
	}

	/**
	 * 创建或更新Codex用户套餐
	 */
	@Override
	public ClaudeCodeResp createOrUpdateCodexUserPackageApi(Long userId, String planName, Integer openaiDailyLimit, Integer openaiQuota, Date expiryTime) throws Exception {
		Map<String, Object> params = new HashMap<>();
		params.put("plan_name", planName.replaceAll(";", ""));
		params.put("openai_daily_limit", openaiDailyLimit);
		params.put("openai_quota", openaiQuota);
		params.put("expire_time", DateUtil.format(expiryTime, "yyyy-MM-dd HH:mm:ss"));
		//claude 类型
		params.put("service_type", "openai");

		String planUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", userId);
		ClaudeCodeResp codexResp = executeCodexPostApi(planUrl, Jsons.toJson(params));

		if (!"success".equals(codexResp.getMessage())) {
			log.info("用户codex用户:{}套餐:{}创建或更新失败，info:{}", userId, planName, codexResp.getMessage());
			throw BusinessRuntimeException.getInstance("调用codex 套餐接口失败");
		}

		return codexResp;
	}

	@Override
	public CodexDeductResp getDeductMoney(Long userId, Long relationId) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		CodexDeductResp codexDeductResp = new CodexDeductResp();
		List<Long> sendCodexSkuIds = skuMapper.selectList(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID).eq(GoodsDonSku::getIsCodex, Boolean.TRUE)).stream().map(GoodsDonSku::getId).collect(Collectors.toList());
		if (CollUtil.isNotEmpty(sendCodexSkuIds)) {
			GroupsRelationView ccRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder().field(GroupsRelationView::getSkuId, sendCodexSkuIds).op(Operator.InList).field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan).field(GroupsRelationView::getUserId, userIdList).op(Operator.InList).field(GroupsRelationView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID).build());
			if (ccRelationView != null) {
				codexDeductResp.setIsDeduct(Boolean.FALSE);
				return codexDeductResp;
			}
		}
		MapBuilder builder = MapUtils.builder();
		if (relationId != null) {
			builder.field(GroupsRelationView::getId, relationId);
		}
		GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, builder
				.field(GroupsRelationView::getGoodsId, Constant.CODEX_GOODS_ID)
				.field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
				.field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
				.build());
		BigDecimal deductMoney;
		if (groupsRelationView == null || groupsRelationView.getExpiryTime().before(DateTime.now())) {
			deductMoney = BigDecimal.ZERO;
		} else {
			relationId = groupsRelationView.getId();
			CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"));
			Assert.notNull(codexUser, "系统异常，请联系客服");
			deductMoney = getFinalDeductMoney(relationId, groupsRelationView.getSkuId(), codexUser.getRenewSkuId(), codexUser.getRenewOrderId(), codexUser.getRenewExpiryTime(), groupsRelationView.getStartTime(), groupsRelationView.getExpiryTime(), DateTime.now(), userIdList);
		}
		codexDeductResp.setDeductMoney(deductMoney);
		return codexDeductResp;
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public OrderDon deductSubmitOrder(CodexUpgradePayReq payReq) throws Exception {
		Long userId = payReq.getUserId();
		//codex 车票id
		Long relationId = payReq.getRelationId();
		CodexDeductResp codexDeductResp = getDeductMoney(userId, relationId);
		if (!codexDeductResp.getIsDeduct()) {
			throw BusinessRuntimeException.getInstance("你存在claude code 无法抵扣");
		}
		//抵扣金额
		BigDecimal deductMoney = codexDeductResp.getDeductMoney();
		Long skuId = payReq.getSkuId();

		GoodsDonSku sku = skuMapper.selectById(skuId);
		if (sku == null || sku.getGoodsId() != Constant.CLAUDE_CODE_GOODS_ID || !sku.getIsCodex()) {
			throw BusinessRuntimeException.getInstance("系统异常，请刷新页面重试");
		}
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		int noPayCount = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class).in(OrderDon::getUserId, userIdList).eq(OrderDon::getGoodsId, sku.getGoodsId())
				.eq(OrderDon::getStatus, OrderDon.Status.noPayment.toString()));
		if (noPayCount > 0) {
			throw new BusinessRuntimeException("您有未支付订单.");
		}
		String cacheKye = "codex_deduct_cache_key:" + relationId;
		boolean b = redisService.setNx(cacheKye, relationId, 10L);
		if (!b) {
			throw BusinessRuntimeException.getInstance("系统繁忙，请刷新页面重试");
		}
		CouponUser couponUser = null;
		if (payReq.getCouponId() != null) {
			CouponPopularizeDto couponPopularizeDto = checkCouponStatus(skuId, null, payReq.getCouponId(), userId, false);
			//记录优惠券使用状态
			couponUser = couponStatusRecord(null, payReq.getCouponId(), userId, couponPopularizeDto);
		}

		OrderDon orderDon;
		try {
			orderDon = new OrderDon();
			orderDon.setGoodsId(sku.getGoodsId());
			orderDon.setSkuId(sku.getId());
			orderDon.setUserId(userId);
			//优惠 --> 订单金额
			deductOrderMoney(orderDon, couponUser);
			orderDon.setMoney(sku.getPrice().subtract(deductMoney));
			orderDon.setType(OrderDon.Type.ALI_PAY);

			/* 生成订单 */
			String donNo = SEQUENCE.nextId().toString();
			orderDon.setOrderNo(donNo);
			orderDon.setStatus(OrderDon.Status.noPayment);

			//锁一个cc的车票id
			//是否存在无赠送的claude code 直接原规格上抵扣
			List<Long> sendCodexSkuIds = skuMapper.selectList(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID).eq(GoodsDonSku::getIsCodex, Boolean.TRUE)).stream().map(GoodsDonSku::getId).collect(Collectors.toList());
			//cc车票id
			Long ccRelationId = null;
			if (CollUtil.isEmpty(sendCodexSkuIds)) {
				//是否存在cc
				Integer selectCount = claudeCodeUserMapper.selectCount(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList));
				if (selectCount > 0) {
					throw BusinessRuntimeException.getInstance("你存在claude code 无法抵扣");
				}
			} else {
				GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
						.field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
						.field(GroupsRelationView::getSkuId, sendCodexSkuIds).op(Operator.NotIn)
						.field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
						.build());
				if (groupsRelationView != null) {
					ccRelationId = groupsRelationView.getId();
				}
			}

			GroupsRelation relation = getClaudeCodeRelation(userId, sku);
			orderDon.setRelationId(relation.getId());
			orderDonMapper.insert(orderDon);

			//记录抵扣记录
			CodexDeductRecord codexDeductRecord = new CodexDeductRecord();
			codexDeductRecord.setCcRelationId(ccRelationId);
			codexDeductRecord.setOrderId(orderDon.getId());
			codexDeductRecord.setRelationId(relationId);
			codexDeductRecordMapper.insert(codexDeductRecord);
		} finally {
			if (redisService.hasKey(cacheKye)) {
				redisService.del(cacheKye);
			}
		}
		return orderDon;
	}

	@Override
	public Boolean getUserSubs(Long userId) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		//是否有该车票
		GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
				.field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
				.field(GroupsRelationView::getGoodsId, Constant.CODEX_GOODS_ID)
				.field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
				.build());
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
		//车票不存在
		if (groupsRelationView == null) {
			//套餐是否存在
			if (codexUser != null) {
				//清除用户套餐
				if (delUserPackages(codexUser.getUserId())) {
					codexUserMapper.deleteById(codexUser.getId());
				}
			}
			return false;
		}
		return true;
	}


	@Override
	public CodexUserInfoView getUserSubsInfo(long userId) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		//是否有该车票
		GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
				.field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
				.field(GroupsRelationView::getGoodsId, Constant.CODEX_GOODS_ID)
				.field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
				.build());
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
		//车票不存在
		if (groupsRelationView == null) {
			//套餐是否存在
			if (codexUser != null) {
				//清除用户套餐
				if (delUserPackages(codexUser.getUserId())) {
					codexUserMapper.deleteById(codexUser.getId());
				}
			}
			return null;
		}

		GoodsDonSku sku = null;
		if (codexUser == null) {
			OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
					.eq(OrderDon::getGoodsId, Constant.CODEX_GOODS_ID)
					.eq(OrderDon::getRelationId, groupsRelationView.getId())
					.in(OrderDon::getUserId, userIdList)
					.notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
					.orderByDesc(OrderDon::getId)
					.last("limit 1"));
			if (orderDon != null) {
				sku = skuMapper.selectById(orderDon.getSkuId());
				createOrUpdateCodexUserInfo(orderDon.getId(), orderDon.getRelationId(), orderDon.getUserId(), sku, orderDon.getOrderType());
			} else {
				//试用车票
				Long skuId = groupsRelationView.getSkuId();
				sku = skuMapper.selectById(skuId);
				createOrUpdateCodexUserInfo(null, groupsRelationView.getId(), groupsRelationView.getUserId(), sku, null);
			}
			codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
		} else {
			codexUser.setExpiryTime(groupsRelationView.getExpiryTime());
			codexUserMapper.updateById(codexUser);
		}
		//续费升级
		if (codexUser.getRenewSkuId() != null) {
			sku = skuMapper.selectById(codexUser.getRenewSkuId());
		}
		if (sku == null) {
			sku = skuMapper.selectById(groupsRelationView.getSkuId());
		}
		//是否需要重试更新 cladueCode userInfo信息
		if (codexUser.getIsRetry()) {
			try {
				ClaudeCodeResp codeUserPackage = createOrUpdateCodexUserPackageApi(codexUser.getUserId(), codexUser.getPlanName(), codexUser.getOpenaiDailyLimit(), codexUser.getOpenaiQuota(), codexUser.getExpiryTime());
				if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
					codexUser.setIsRetry(Boolean.TRUE);
					codexUserMapper.updateById(codexUser);
				} else {
					codexUser.setIsRetry(Boolean.FALSE);
					codexUserMapper.updateById(codexUser);
				}
			} catch (Exception e) {

			}
		}
		return CodexUserInfoView.builder()
				.planName(codexUser.getPlanName())
				.relationId(codexUser.getRelationId())
				.openaiDailyLimit(codexUser.getOpenaiDailyLimit())
				.openaiQuota(codexUser.getOpenaiQuota())
				.expiryTime(codexUser.getExpiryTime())
				.renewSkuId(Optional.ofNullable(codexUser.getRenewSkuId()).orElse(groupsRelationView.getSkuId()))
				.renewOrderId(codexUser.getRenewOrderId())
				.renewExpiryTime(codexUser.getRenewExpiryTime())
				.build();
	}

	private GroupsRelation getClaudeCodeRelation(Long userId, GoodsDonSku sku) {
		//获取车票车位
		GroupsRelation relation = getRelation(sku);
		//锁定座位
		setRelation(relation);
		//校验座位
		int update = relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
				.set(GroupsRelation::getUserId, userId)
				.eq(GroupsRelation::getUserId, 0)
				.eq(GroupsRelation::getId, relation.getId()));
		if (update == 0) {
			throw BusinessRuntimeException.getInstance("系统繁忙，请重试");
		}
		relation.setUserId(userId);
		//重新置为锁定
		relation.setStatus(GroupsRelation.Status.locking);
		relationMapper.updateById(relation);
		return relation;
	}

	private GroupsRelation getRelation(GoodsDonSku sku) {
		GroupsRelation relation = null;
		Integer maxNum = sku.getNum();
		GroupsTrips groups = groupsMapper.selectTicketGroups(sku.getId(), GroupsTrips.Status.validity, maxNum, null, null);
		if (groups == null) {
			//待发车
			groups = groupsMapper.selectTicketGroups(sku.getId(), GroupsTrips.Status.waiting, maxNum, null, null);
		}
		//新增空车队
		if (groups == null) {
			relation = groupsFuncService.createNewGroupsTrips(sku);
		}
		//获取车位
		if (relation == null) {
			//寻找快满编车队进行占座
			relation = relationMapper.selectRandomOneRelationByGroupsId(groups.getId());
			if (relation == null) {
				throw BusinessRuntimeException.getInstance("系统繁忙,请重试");
			}
		}
		return relation;
	}

	public BigDecimal getFinalDeductMoney(Long relationId, Long relationSkuId, Long renewSkuId, Long renewOrderId, Date renewExpiryTime, Date relationStartTime, Date relationExpiryTime, DateTime now, List<Long> userIdList) {
		BigDecimal deductMoney = BigDecimal.ZERO;
		//一个月当30天算单价 往上取整
		//续费规格
		if (renewSkuId != null && renewExpiryTime.compareTo(now) > 0) {
			OrderDon renewOrderDon = orderDonMapper.selectById(renewOrderId);
			BigDecimal orderMoney = renewOrderDon.getMoney().add(Optional.ofNullable(renewOrderDon.getBalance()).orElse(BigDecimal.ZERO));
			GoodsDonSku presentSku = skuMapper.selectById(renewSkuId);
			if (orderMoney.compareTo(BigDecimal.ZERO) == 0) {
				orderMoney = presentSku.getPrice();
			}
			Long betweenDay = DateUtil.betweenDay(now, renewExpiryTime, false) + 1;
			//当天购买的按规格原价抵扣
			BigDecimal renewDeductMoney;
			if (now.toDateStr().equals(DateUtil.format(renewOrderDon.getCreatedTime(), "yyyy-MM-dd"))) {
				renewDeductMoney = orderMoney;
				deductMoney = deductMoney.add(renewDeductMoney);
				if (presentSku.getDays() != null) {
					relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -presentSku.getDays());
				} else {
					relationExpiryTime = DateUtil.offsetMonth(relationExpiryTime, -presentSku.getMonths());
				}
			} else {
				//此次续费规格单价
				BigDecimal single = getPayOrderSingle(orderMoney, presentSku);
				//该车票抵扣金额
				renewDeductMoney = single.multiply(BigDecimal.valueOf(betweenDay));
				log.info("codex车票id:{}目前续费升级规格可抵扣的金额为：{}", relationId, renewDeductMoney);
				deductMoney = deductMoney.add(renewDeductMoney);
				relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -betweenDay.intValue());
			}
			//上一个续费升级规格
			List<OrderDon> orderDOns = codexUserRenewExpiryRecordMapper.getOtherRenewSkus(renewOrderId, relationId, userIdList);
			OrderDon presentRenewOrderDon = renewOrderDon;
			for (OrderDon thisRenewOrderDon : orderDOns) {
				Long skuId = thisRenewOrderDon.getSkuId();
				GoodsDonSku thisRenewSku = skuMapper.selectById(skuId);
				BigDecimal thisOrderMoney = thisRenewOrderDon.getMoney().add(Optional.ofNullable(thisRenewOrderDon.getBalance()).orElse(BigDecimal.ZERO));
				if (thisOrderMoney.compareTo(BigDecimal.ZERO) == 0) {
					thisOrderMoney = thisRenewSku.getPrice();
				}
				//当天购买的按规格原价抵扣
				BigDecimal thisRenewDeductMoney = BigDecimal.ZERO;
				if (now.toDateStr().equals(DateUtil.format(thisRenewOrderDon.getCreatedTime(), "yyyy-MM-dd"))) {
					thisRenewDeductMoney = thisOrderMoney;
					deductMoney = deductMoney.add(thisRenewDeductMoney);
					if (thisRenewSku.getDays() != null) {
						relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -thisRenewSku.getDays());
					} else {
						relationExpiryTime = DateUtil.offsetMonth(relationExpiryTime, -thisRenewSku.getMonths());
					}
				} else {
					//此次续费订单过期时间
					Date thisOrderExpiryTime;
					if (thisRenewSku.getDays() != null) {
						thisOrderExpiryTime = DateUtil.offsetDay(thisRenewOrderDon.getCreatedTime(), thisRenewSku.getDays());
					} else {
						thisOrderExpiryTime = DateUtil.offsetMonth(thisRenewOrderDon.getCreatedTime(), thisRenewSku.getMonths());
					}
					//续费同规格不处理
					if (!ObjectUtil.equal(thisRenewOrderDon.getSkuId(), presentRenewOrderDon.getSkuId())) {
						//先扣除已使用的天数
						//相差多少天
						Long thisRenewBetDay = DateUtil.betweenDay(thisRenewOrderDon.getCreatedTime(), presentRenewOrderDon.getCreatedTime(), false);
						//扣除已使用的
						thisOrderExpiryTime = DateUtil.offsetDay(thisOrderExpiryTime, -thisRenewBetDay.intValue());
					}
					//此订单过期时间
					if (thisOrderExpiryTime.compareTo(now) > 0) {
						//距离过期还剩多少天
						Long thisDeductBetweenDay = DateUtil.betweenDay(now, thisOrderExpiryTime, false) + 1;
						if (thisDeductBetweenDay != 0) {
							//此次续费规格单价
							BigDecimal single = getPayOrderSingle(thisOrderMoney, thisRenewSku);
							//该车票抵扣金额
							thisRenewDeductMoney = single.multiply(BigDecimal.valueOf(thisDeductBetweenDay));
							deductMoney = deductMoney.add(thisRenewDeductMoney);
						}
						//目前级别续费订单
						presentRenewOrderDon = thisRenewOrderDon;
						relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -thisDeductBetweenDay.intValue());
					}
				}
				log.info("codex车票id:{}目前次一级规格：{}可抵扣的金额为：{}", relationId, thisRenewSku.getSpecVal(), thisRenewDeductMoney);

			}
		}
		if (relationExpiryTime.after(now)) {
			//该车票抵扣金额
			BigDecimal deductMoneyFromTicket = getDeductMoneyFromTicket(relationId, userIdList, relationSkuId, now, relationStartTime, relationExpiryTime);
			deductMoney = deductMoney.add(deductMoneyFromTicket);
		}
		log.info("codex车票id:{}最终到期时间为：{}车票可返回 抵扣金额:{}", relationId, DateUtil.format(relationExpiryTime, "yyyy-MM-dd HH:mm:ss"), deductMoney);
		return deductMoney;
	}

	private Retryer<ClaudeCodeResp> getApiRetryer(int wait, int stop) {
		return RetryerBuilder.<ClaudeCodeResp>newBuilder().retryIfResult(result -> result == null).retryIfException().withWaitStrategy(WaitStrategies.fixedWait(wait, TimeUnit.SECONDS)).withStopStrategy(StopStrategies.stopAfterAttempt(stop)).build();
	}

	/**
	 * Codex POST请求
	 */
	public ClaudeCodeResp executeCodexPostApi(String url, String body) {
		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
		try {
			return build.call(() -> {
				try {
					HttpResponse execute = HttpUtil.createPost(url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).body(body).execute();
					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
					if (!"success".equals(resp.getMessage())) {
						log.error("codex POST URL:{}接口返回msg：{}", url, resp.getMessage());
					}
					return resp;
				} catch (Exception e) {
					log.error("codex POST请求异常: url={}, error={}", url, StringUtil.getErrorText(e));
					return null;
				}
			});
		} catch (ExecutionException | com.github.rholder.retry.RetryException e) {
			log.info("重试调用codex POST请求 url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
			throw BusinessRuntimeException.getInstance("创建或更新codex user失败");
		}
	}

	/**
	 * codex用户信息重试更新信息
	 */
	public void setCodexUserRetryUpdateInfo(Long relationId) {
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"));
		if (codexUser != null) {
			codexUser.setIsRetry(Boolean.TRUE);
			codexUserMapper.updateById(codexUser);
		}
	}

	@Override
	public ClaudeCodeResp getUserOpenAIUsage(Long userId, String period) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));

		if (codexUser == null) {
			return null;
		}
		// 调用Codex API获取实时使用统计
		String usageUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/usage?period=%s", codexUser.getUserId(), period);
		ClaudeCodeResp codexResp = executeCodexGetApi(usageUrl);
		return codexResp;
	}

	@Override
	public ClaudeCodeResp updateUserOpenAIDailyLimit(Long userId, UpdateDailyLimitRequest request) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));

		if (codexUser == null) {
			throw new BusinessRuntimeException("用户未开通Codex服务");
		}
		Integer dailyLimit = request.getDailyLimit();
		Integer totalQuota = request.getTotalQuota();

		// 验证每日限额参数
		if (dailyLimit == null || dailyLimit <= 0) {
			throw new BusinessRuntimeException("每日限额必须大于0");
		}
		
		// 保存原始值用于回滚
		Integer originalDailyLimit = codexUser.getOpenaiDailyLimit();
		
		// 更新数据库中的每日限额
		codexUser.setOpenaiDailyLimit(dailyLimit);
		codexUserMapper.updateById(codexUser);
		
		try {
			// 调用Codex API更新每日限额
			String updateUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/limit", codexUser.getUserId());
			Map<String, Object> params = new HashMap<>();
			params.put("daily_limit", dailyLimit);
			params.put("total_quota", totalQuota);

			ClaudeCodeResp codexResp = executeCodexPostApi(updateUrl, Jsons.toJson(params));
			
			if (!"success".equals(codexResp.getMessage())) {
				log.error("更新用户{}每日限额{}失败: {}", userId, dailyLimit, codexResp.getMessage());
				// API调用失败时回滚数据库更新
				codexUser.setOpenaiDailyLimit(originalDailyLimit);
				codexUserMapper.updateById(codexUser);
				throw new BusinessRuntimeException("更新每日限额失败");
			}
			
			log.info("成功更新用户{}每日限额为{}", userId, dailyLimit);
			return codexResp;
			
		} catch (Exception e) {
			log.error("更新用户{}每日限额{}异常: {}", userId, dailyLimit, StringUtil.getErrorText(e));
			// 异常时回滚数据库更新
			codexUser.setOpenaiDailyLimit(originalDailyLimit);
			codexUserMapper.updateById(codexUser);
			throw new BusinessRuntimeException("更新每日限额失败");
		}
	}

	@Override
	public ClaudeCodeResp getSystemMetrics(String period, String metric) {
		try {
			// 构建系统指标API URL
			String metricsUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/system/metrics");
			
			// 添加查询参数
			List<String> queryParams = new ArrayList<>();
			if (period != null && !period.isEmpty()) {
				queryParams.add("period=" + period);
			}
			if (metric != null && !metric.isEmpty()) {
				queryParams.add("metric=" + metric);
			}
			
			if (!queryParams.isEmpty()) {
				metricsUrl += "?" + String.join("&", queryParams);
			}
			
			// 调用Codex API获取系统指标
			ClaudeCodeResp codexResp = executeCodexGetApi(metricsUrl);
			
			if (codexResp == null) {
				log.error("获取系统指标失败: API返回null");
				throw new BusinessRuntimeException("获取系统指标失败");
			}
			
			log.info("成功获取系统指标, period={}, metric={}", period, metric);
			return codexResp;
			
		} catch (Exception e) {
			log.error("获取系统指标异常, period={}, metric={}, error={}", period, metric, StringUtil.getErrorText(e));
			throw new BusinessRuntimeException("获取系统指标失败");
		}
	}
	
	@Override
	public ClaudeCodeResp getJavaUserDashboard(Long userId) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));

		if (codexUser == null) {
			return null;
		}

		// 调用Codex API获取用户控制台数据
		String dashboardUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/dashboard", codexUser.getUserId());
		ClaudeCodeResp codexResp = executeCodexGetApi(dashboardUrl);
		return codexResp;
	}
	
	@Override
	public ClaudeCodeResp getJavaUserAnalytics(Long userId, String start, String end, Integer page, Integer limit, String order) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));

		if (codexUser == null) {
			return null;
		}

		if (start == null) {
			DateTime now = DateTime.now();
			start = DateUtil.offsetDay(now, -1).toString();
			end = now.toString();
		}

		// 调用Codex API获取用户分析数据
		String analyticsUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/analytics?start=%s&end=%s&page=%s&limit=%s&order=%s", codexUser.getUserId(), start, end, page, limit, order);
		ClaudeCodeResp codexResp = executeCodexGetApi(analyticsUrl);

		return codexResp;
	}

	@Override
	public void delCodexUser(Long userId, Long relationId) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).eq(CodexUser::getRelationId, relationId).last("limit 1"));
		if (codexUser != null) {
			codexUserMapper.deleteById(codexUser.getId());
		}
	}

	@Override
	public void createOrUpdateCodexUserInfo(Long orderId, Long relationId, Long userId, GoodsDonSku sku, Integer orderType) {
		//新增或续费升级
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getId, relationId).in(GroupsRelation::getUserId, userIdList));
		GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
		GoodsDonSku relationSku = skuMapper.selectById(groupsTrips.getSkuId());
		Long thisCodeOriSkuId = relationSku.getId();
		Long relationUserId = relation.getUserId();
		//此时车票的套餐规格积分
		Integer thisRelationDayilyLimit = null;
		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"));
		if (codexUser != null) {
			thisRelationDayilyLimit = codexUser.getOpenaiDailyLimit();
		}
		Date expiryTime = relation.getExpiryTime();
		Integer openaiDailyLimit = sku.getOpenaiDailyLimit();
		Integer openaiQuota = sku.getOpenaiQuota();
		Long skuId = sku.getId();
		Boolean isUpgrade = false;
		Date renewExpiryTime = null;
		//若是续费升级 记录此时续费升级的过期时间
		if (!ObjectUtil.equal(thisCodeOriSkuId, skuId)) {
			//非车票原规格id 续费升级记录
			saveCodexRenewExpiryRecord(orderId, relationUserId, relationId, skuId);
			//是否需要修改当前claude code user 套餐等级
			if (thisRelationDayilyLimit != null && thisRelationDayilyLimit <= openaiDailyLimit) {
				if (sku.getDays() != null) {
					renewExpiryTime = DateUtil.offsetDay(DateTime.now(), sku.getDays());
				} else {
					renewExpiryTime = DateUtil.offsetMonth(DateTime.now(), sku.getMonths());
				}
				isUpgrade = true;
			}
		}
		//更新db codexUser
		generateOrUpdateCodexUser(relationUserId, relationId, openaiDailyLimit, openaiQuota, expiryTime, isUpgrade, orderId, skuId, renewExpiryTime, sku.getSpecVal(), userIdList, Boolean.TRUE);

		try {
			//获取最新的claude code user
			codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"));
			//生成codex或更新用户套餐
			ClaudeCodeResp codeUserPackage = createOrUpdateCodexUserPackageApi(relation.getUserId(), codexUser.getPlanName(), codexUser.getOpenaiDailyLimit(), codexUser.getOpenaiQuota(), codexUser.getExpiryTime());
			if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
				//重试更新code userInfo数据
				setCodexUserRetryUpdateInfo(relationId);
				return;
			}
		} catch (Exception e) {
			log.error("生成或更新claude code用户：{}套餐skuId:{} 失败，error_info:{}", userId, skuId, StringUtil.getErrorText(e));
			//重试更新code userInfo数据
			setCodexUserRetryUpdateInfo(relationId);
		}
	}

	@Override
	public void updateCodexUserPackageInfo(CodexUser codexUser, Date expiryTime, GoodsDonSku finalSku) {
		try {
			ClaudeCodeResp codeUserPackage = createOrUpdateCodexUserPackageApi(codexUser.getUserId(), codexUser.getPlanName(), codexUser.getOpenaiDailyLimit(), codexUser.getOpenaiQuota(), expiryTime);
			if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
				//重试标记
				codexUser.setIsRetry(Boolean.TRUE);
				codexUserMapper.updateById(codexUser);
				return;
			}
		} catch (Exception e) {
			codexUser.setIsRetry(Boolean.TRUE);
			codexUserMapper.updateById(codexUser);
		}
	}

	private void generateOrUpdateCodexUser(Long relationUserId, Long relationId, Integer openaiDailyLimit, Integer openaiQuota, Date expiryTime, Boolean isUpgrade, Long orderId, Long renewSkuId, Date renewExpiryTime, String planName, List<Long> userIdList, Boolean isPay) {
		CodexUser codexUser = Optional.ofNullable(codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"))).orElse(new CodexUser());
		if (isUpgrade) {
			codexUser.setRenewOrderId(orderId);
			codexUser.setRenewSkuId(renewSkuId);
			codexUser.setRenewExpiryTime(renewExpiryTime);
			codexUser.setPlanName(planName);
			codexUser.setOpenaiDailyLimit(openaiDailyLimit);
			codexUser.setOpenaiQuota(openaiQuota);
		}
		codexUser.setIsPay(isPay);
		codexUser.setUserId(relationUserId);
		codexUser.setRelationId(relationId);
		codexUser.setExpiryTime(expiryTime);
		if (codexUser.getId() == null) {
			codexUser.setPlanName(planName);
			codexUser.setOpenaiDailyLimit(openaiDailyLimit);
			codexUser.setOpenaiQuota(openaiQuota);
		}
		if (codexUser.getId() == null) {
			try {
				codexUserMapper.insert(codexUser);
			} catch (DuplicateKeyException e) {
				log.info("插入codex user 重复");
			}
		} else codexUserMapper.updateById(codexUser);
	}

	private void saveCodexRenewExpiryRecord(Long orderId, Long relationUserId, Long relationId, Long skuId) {
		CodexUserRenewExpiryRecord renewExpiryRecord = new CodexUserRenewExpiryRecord();
		renewExpiryRecord.setOrderId(orderId);
		renewExpiryRecord.setUserId(relationUserId);
		renewExpiryRecord.setRelationId(relationId);
		renewExpiryRecord.setRenewSkuId(skuId);
		codexUserRenewExpiryRecordMapper.insert(renewExpiryRecord);
	}

	/**
	 * Codex DELETE请求
	 */
	public ClaudeCodeResp executeCodexDeleteApi(String url) {
		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
		try {
			return build.call(() -> {
				try {
					HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url)
							.header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
							.setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
							.execute();
					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
					if (!"success".equals(resp.getMessage())) {
						log.error("codex DELETE URL:{}接口返回msg：{}", url, resp.getMessage());
					}
					return resp;
				} catch (Exception e) {
					log.error("codex DELETE请求异常: url={}, error={}", url, StringUtil.getErrorText(e));
					return null;
				}
			});
		} catch (ExecutionException | com.github.rholder.retry.RetryException e) {
			log.error("重试调用codex DELETE请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
			throw BusinessRuntimeException.getInstance("删除操作失败");
		}
	}

	/**
	 * Codex GET请求
	 */
	public ClaudeCodeResp executeCodexGetApi(String url) {
		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
		try {
			return build.call(() -> {
				try {
					HttpResponse execute = HttpUtil.createGet(url)
							.header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
							.setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
							.execute();
					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
					if (!"success".equals(resp.getMessage())) {
						log.error("codex GET URL:{}接口返回msg：{}", url, resp.getMessage());
					}
					return resp;
				} catch (Exception e) {
					log.error("codex GET请求异常: url={}, error={}", url, StringUtil.getErrorText(e));
					return null;
				}
			});
		} catch (ExecutionException | com.github.rholder.retry.RetryException e) {
			log.error("重试调用codex GET请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
			throw BusinessRuntimeException.getInstance("获取codex使用统计失败");
		}
	}

	/**
	 * 获取订单单价
	 */
	public BigDecimal getPayOrderSingle(BigDecimal orderMoney, GoodsDonSku sku) {
		//此次续费规格单价
		BigDecimal single;
		//区分天/月
		if (sku.getDays() != null) {
			single = orderMoney.divide(BigDecimal.valueOf(sku.getDays()), 0, RoundingMode.HALF_UP);
		} else {
			single = orderMoney.divide(BigDecimal.valueOf(sku.getMonths()).multiply(BigDecimal.valueOf(30)), 0, RoundingMode.HALF_UP);
		}
		return single;
	}


	/**
	 * 获取车票可抵扣金额
	 */
	public BigDecimal getDeductMoneyFromTicket(Long relationId, List<Long> userIdList, Long skuId, DateTime now, Date relationStartTime, Date relationExpiryTime) {
		List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
				.eq(OrderDon::getRelationId, relationId)
				.in(OrderDon::getUserId, userIdList)
				.eq(OrderDon::getSkuId, skuId)
				.notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
				.orderByDesc(OrderDon::getId));
		//部分退款
		if (orderDonList.isEmpty()) {
			orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
					.eq(OrderDon::getRelationId, relationId)
					.in(OrderDon::getUserId, userIdList)
					.eq(OrderDon::getSkuId, skuId)
					.notIn(OrderDon::getStatus, Constant.noOrderStatus)
					.orderByDesc(OrderDon::getId));
		}
		//原车票订单总实付金额
		BigDecimal totalOrderMoney = BigDecimal.ZERO;
		//原车票订单总天数
		Integer totalDays = 0;
		for (OrderDon orderDon : orderDonList) {
			GoodsDonSku sku = skuMapper.selectById(skuId);
			BigDecimal thisOrderMoney = orderDon.getMoney().add(Optional.ofNullable(orderDon.getBalance()).orElse(BigDecimal.ZERO)).subtract(Optional.ofNullable(orderDon.getRefundMoney()).orElse(BigDecimal.ZERO));
			if (thisOrderMoney.compareTo(BigDecimal.ZERO) == 0) {
				thisOrderMoney = sku.getPrice();
			}
			totalOrderMoney = totalOrderMoney.add(thisOrderMoney);
			//总时间
			if (sku.getDays() != null) {
				totalDays += sku.getDays();
			} else {
				totalDays += sku.getMonths() * 30;
			}
			//原订单数
			if (orderDonList.size() == 1) {
				//此次订单过期时间
				Date thisOrderExpiryTime;
				if (sku.getDays() != null) {
					thisOrderExpiryTime = DateUtil.offsetDay(orderDon.getCreatedTime(), sku.getDays());
				} else {
					thisOrderExpiryTime = DateUtil.offsetMonth(orderDon.getCreatedTime(), sku.getMonths());
				}
				//当天购买的按规格原价抵扣
				if (now.toDateStr().equals(DateUtil.format(relationStartTime, "yyyy-MM-dd")) && (DateUtil.betweenDay(thisOrderExpiryTime, relationExpiryTime, true) == 0)) {
					return thisOrderMoney;
				}
			}
		}
		Long thisDeductBetweenDay = DateUtil.betweenDay(now, relationExpiryTime, false) + 1;
		BigDecimal single = totalOrderMoney.divide(BigDecimal.valueOf(totalDays), 0, RoundingMode.HALF_UP);
		//该车票抵扣金额
		BigDecimal deductMoney = single.multiply(BigDecimal.valueOf(thisDeductBetweenDay));
		return deductMoney;
	}

	public void setRelation(GroupsRelation relation) {
		Long relationId = relation.getId();
		Long userId = relation.getUserId();
		Long groupsId = relation.getGroupsId();
		GroupsRelation.Status status = relation.getStatus();
		String relation_num_key = RedisKey.GROUPS_RELATION_NUM_KEY + relationId;
		if (!redisService.setNx(relation_num_key, userId, 60 * 5L)) {
			GroupsRelation dbRelation = relationMapper.selectById(relationId);
			if (dbRelation.getUserId() != 0) {
				log.info("=====>用户:{}未抢到座位:{}", userId, relationId);
				throw new BusinessRuntimeException("系统繁忙，请重试...");
			}
		}
		if (status == GroupsRelation.Status.outside) {
			return;
		}
		int count = groupsMapper.decrAvailableNum(groupsId);
		if (count == 0) {
			log.error("车位异常 groupId:{}", groupsId);
			groupsMapper.updateAvailableNum(groupsId);
			//清除座位缓存key
			delRelationKey(relationId, userId);
			throw new BusinessRuntimeException("车位异常");
		}
	}

	/**
	 * 清除座位缓存key
	 */
	public void delRelationKey(Long relationId, Long userId) {
		String relation_num_key = RedisKey.GROUPS_RELATION_NUM_KEY + relationId;
		Object object = redisService.get(relation_num_key);
		if (object != null) {
			try {
				Long keyUserId = Long.parseLong(object.toString());
				//清除车票key
				if (ObjectUtil.equal(userId, keyUserId)) {
					redisService.del(relation_num_key);
				}
			} catch (Exception e) {
				log.error("删除缓存key错误:{}", StringUtil.getErrorText(e));
			}
		}
	}

	public CouponPopularizeDto checkCouponStatus(Long skuId, String couponExCode, Long couponId, Long userId, Boolean isRenew) throws Exception {
		log.info("开始校验兑换码:{},优惠券id:{}状态", couponExCode, couponId);
		//实物还是虚物商品
		GoodsDonSku goodsDonSku = skuMapper.selectById(skuId);
		GoodsDon goodsDon = goodsDonMapper.selectById(goodsDonSku.getGoodsId());
		if (StrUtil.isNotBlank(couponExCode) && couponId != null) {
			throw BusinessRuntimeException.getInstance("优惠券与优惠码不可同时使用..");
		}
		if (StrUtil.isNotBlank(couponExCode)) {
			CouponPopularizeDto exists = couponMapper.checkExCode(couponExCode);
			if (exists == null) {
				throw BusinessRuntimeException.getInstance("该优惠码不存在");
			}
			//推广码
			if (exists.getIsGeneral() != null) {
				if (exists.getIsGeneral() && userId.equals(exists.getUserId())) {
					throw BusinessRuntimeException.getInstance("不可以使用自己的优惠码");
				}
				if (!exists.getIsGeneral()) {
					UserDistribute userDistribute = userDistributeMapper.selectById(exists.getDistributeId());
					if (userDistribute != null && userDistribute.getUserId().equals(userId)) {
						throw BusinessRuntimeException.getInstance("不可以使用自己的优惠码");
					}
				}
				//是否有上下级关系
				if (exists.getIsGeneral()) {
					UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class)
							.eq(UserDistributeShared::getUserId, userId).last("limit 1"));
					if (userDistributeShared == null) {
						//是否是 当天注册新用户 且下过单
						User user = userMapper.selectById(userId);
						if (user.getCreatedTime().before(DateUtil.beginOfDay(DateTime.now()))) {
							throw BusinessRuntimeException.getInstance("该优惠码只适用于新用户");
						}
						CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
						if (couponNewUserView != null)
							throw BusinessRuntimeException.getInstance("该优惠码只适用于新用户");
					}
					if (userDistributeShared != null && !userDistributeShared.getSharedId().equals(exists.getUserId())) {
						throw BusinessRuntimeException.getInstance("您已有推广,无法使用其他人推广码");
					}
				}
			}
			checkCouponGoods(goodsDon, skuId, exists.getCouponId(), true);
			//检验是优惠券使用范围
			if (isRenew && exists.getUseScope() == Coupon.UseScope.orders) {
				throw BusinessRuntimeException.getInstance("该优惠码续费时不可使用");
			}
			if (!isRenew && exists.getUseScope() == Coupon.UseScope.renew) {
				throw BusinessRuntimeException.getInstance("该优惠码下单时不可使用");
			}
			if (exists.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("该新用户优惠码有且仅可使用一次");
				}
			}
			if (exists.getIsValidTime() && exists.getValidEndTime().before(DateTime.now())) {
				throw BusinessRuntimeException.getInstance("该优惠码已失效");
			}
			if (exists.getIsValidTime() && exists.getValidStartTime().after(DateTime.now())) {
				throw BusinessRuntimeException.getInstance("该优惠码待生效");
			}
			return exists;
		} else if (couponId != null) {
			CouponUserView couponUserView = beanSearcher.searchFirst(CouponUserView.class, MapUtils.builder()
					.field(CouponUserView::getCouponId, couponId).op(Operator.Equal)
					.field(CouponUserView::getUserId, userId).op(Operator.Equal)
					.build());
			if (couponUserView == null) {
				throw BusinessRuntimeException.getInstance("该优惠券不存在");
			}
			if (couponUserView.getCouponUserStatus() == CouponUser.Status.used) {
				throw BusinessRuntimeException.getInstance("该优惠券已使用");
			}
			couponFontService.setCouponUserStatus(couponUserView, DateTime.now());
			if (couponUserView.getCouponUserStatus() != CouponUser.Status.unused) {
				throw BusinessRuntimeException.getInstance(couponUserView.getReason());
			}
			checkCouponGoods(goodsDon, skuId, couponUserView.getCouponId(), false);
			//检验是优惠券使用范围
			if (isRenew && couponUserView.getUseScope() == Coupon.UseScope.orders) {
				throw BusinessRuntimeException.getInstance("该优惠券续费时不可使用");
			}
			if (!isRenew && couponUserView.getUseScope() == Coupon.UseScope.renew) {
				throw BusinessRuntimeException.getInstance("该优惠券下单时不可使用");
			}
		}
		return null;
	}


	private CouponUser couponStatusRecord(String couponExCode, Long couponId, Long userId, CouponPopularizeDto exists) {
		log.info("兑换码:{},优惠券id:{},更新其优惠券状态", couponExCode, couponId);
		CouponUser couponUser = null;
		if (StrUtil.isNotBlank(couponExCode)) {
			if (exists == null) {
				throw BusinessRuntimeException.getInstance("该优惠码不存在");
			}
			couponUser = new CouponUser();
			couponUser.setCouponId(exists.getCouponId());
			if (exists.getPopularizeId() != null) {
				couponUser.setCouponId(exists.getPopularizeCouponId());
				couponUser.setPopularizeId(exists.getPopularizeId());
			}
			//续费优惠码可重复使用
			if (exists.getUseScope() != Coupon.UseScope.renew) {
				//非渠道推广 推广优惠码只可使用一次
				if ((exists.getPopularizeId() != null && exists.getIsGeneral()) || exists.getPopularizeId() == null) {
					CouponUser received = couponUserMapper.selectOne(Wrappers.lambdaQuery(CouponUser.class).eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, couponUser.getCouponId()).last("limit 1"));
					if (received != null && received.getStatus() != CouponUser.Status.unused) {
						throw BusinessRuntimeException.getInstance("您已使用该优惠码所对应的优惠券");
					}
					couponUser.setUserId(userId);
					couponUser.setStatus(CouponUser.Status.used);
					couponUser.setChannel(CouponUser.Channel.exCode);
					couponFontService.updateCouponUserValidTime(couponUser.getCouponId(), couponUser);
					try {
						couponUserMapper.insert(couponUser);
					} catch (DuplicateKeyException e) {
						log.info("用户已领取该{}优惠券", couponUser.getCouponId());
						throw BusinessRuntimeException.getInstance("您已领取该优惠码对应的优惠券,请使用优惠券");
					}
				}
			}
		} else {
			couponUser = couponUserMapper.selectOne(Wrappers.lambdaQuery(CouponUser.class).eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, couponId).last("limit 1"));
			if (couponUser == null) {
				throw BusinessRuntimeException.getInstance("该优惠券不存在");
			}
			couponUser.setStatus(CouponUser.Status.used);
			couponUserMapper.updateById(couponUser);
		}
		return couponUser;
	}

	public void checkCouponGoods(GoodsDon goodsDon, Long skuId, Long couponId, Boolean isCouponCode) throws Exception {
		if (goodsDon.getType() == 1) {
			CouponSku couponSku = couponSkuMapper.selectOne(Wrappers.lambdaQuery(CouponSku.class)
					.eq(CouponSku::getSkuId, skuId)
					.eq(CouponSku::getCouponId, couponId)
					.select(CouponSku::getId).last("limit 1"));
			if (couponSku == null) {
				throw BusinessRuntimeException.getInstance(String.format("该%s不适用于该规格", isCouponCode ? "优惠码" : "优惠券"));
			}
		} else {
			//实物、潮玩 优惠码优惠券 针对平台
			Long gid = goodsDon.getId();
			CouponSku couponSku = couponSkuMapper.selectOne(Wrappers.lambdaQuery(CouponSku.class)
					.eq(CouponSku::getGoodsId, gid)
					.eq(CouponSku::getCouponId, couponId)
					.select(CouponSku::getId).last("limit 1"));
			if (couponSku == null) {
				throw BusinessRuntimeException.getInstance(String.format("该%s不可用于该商品", isCouponCode ? "优惠码" : "优惠券"));
			}
		}
	}

	/**
	 * 使用优惠营销 订单金额抵扣
	 */
	public void deductOrderMoney(OrderDon orderDon, CouponUser couponUser) throws Exception {
		BigDecimal first_money = orderDon.getMoney();
		//存在优惠券
		if (couponUser != null) {
			Long couponId = couponUser.getCouponId();
			Coupon coupon = couponMapper.getCouponById(couponId);
			BigDecimal couponMoney = null;
			BigDecimal payMoney = orderDon.getMoney();
			BigDecimal needDeductMoney = payMoney;
			if (orderDon.getOriMoney() == null) {
				orderDon.setOriMoney(payMoney);
			}
			if (orderDon.getIsDp() != null && orderDon.getIsDp()) {
				needDeductMoney = needDeductMoney.subtract(orderDon.getDpMoney());
			}
			if (coupon.getType() == Coupon.Type.discount) {
				couponMoney = needDeductMoney.multiply(BigDecimal.valueOf(1).subtract(coupon.getDiscount()));
				//需支付金额
				orderDon.setMoney(payMoney.subtract(couponMoney));

				orderDon.setOriMoney(orderDon.getOriMoney().multiply(coupon.getDiscount()));
				//记录折扣 用于分销
				couponUser.setDiscount(coupon.getDiscount());
				couponUserMapper.updateById(couponUser);
			} else if (coupon.getType() == Coupon.Type.reduce) {
				BigDecimal subtractMoney = payMoney.subtract(coupon.getReduceMoney());
				orderDon.setMoney(subtractMoney);
				couponMoney = coupon.getReduceMoney();

				orderDon.setOriMoney(orderDon.getOriMoney().subtract(coupon.getReduceMoney()));
			}
			if (couponMoney != null && couponMoney.compareTo(first_money) >= 0) {
				throw BusinessRuntimeException.getInstance("支付金额不能小于优惠金额");
			}
			orderDon.setCouponMoney(couponMoney);
			orderDon.setCouponUserId(couponUser.getId());
			orderDon.setCouponId(couponUser.getCouponId());
		}
	}

	private boolean delUserPackages(Long userId) {
		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan?service_type=openai", userId);
		try {
			ClaudeCodeResp claudeCodeResp = executeClaudeCodeDeletedApi(url);
			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
				log.error("删除用户：{} claude code套餐失败：{}", userId, claudeCodeResp.getMessage());
				return Boolean.FALSE;
			}
			return Boolean.TRUE;
		} catch (Exception e) {
			log.error("删除用户:{} claude code套餐报错：{}", userId, StringUtil.getErrorText(e));
		}
		return Boolean.FALSE;
	}

	/**
	 * claude code DELETE请求
	 */
	public ClaudeCodeResp executeClaudeCodeDeletedApi(String url) {
		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
		try {
			return build.call(() -> {
				try {
					HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
					if (!Constant.SUCCESS.equals(resp.getMessage())) {
						log.error("claude code DELETE URL:{}接口返回msg：{}", url, resp.getMessage());
					}
					return resp;
				} catch (HttpException e) {
					return null;
				}
			});
		} catch (ExecutionException | RetryException e) {
			log.error("重试调用claude code DELETE请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
			throw BusinessRuntimeException.getInstance("接口请求失败");
		}
	}
}