package com.cyksj.service.claude.impl;

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.http.HttpException;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.util.Jsons;
import com.cyksj.common.util.StringUtil;
import com.cyksj.mapper.*;
import com.cyksj.mapper.claudecode.ClaudeCodeCreditCardMapper;
import com.cyksj.mapper.claudecode.ClaudeCodeDayResetRecordMapper;
import com.cyksj.mapper.claudecode.ClaudeCodeUserCreditCardRecordMapper;
import com.cyksj.mapper.claudecode.ClaudeCodeUserResetRecordMapper;
import com.cyksj.mapper.manage.distribute.DistributePointsExchangeMoneyMapper;
import com.cyksj.mapper.manage.distribute.DistributeWaitingSendPointsMapper;
import com.cyksj.model.entity.*;
import com.cyksj.model.manage.views.GroupsRelationView;
import com.cyksj.model.request.ClaudeCodeApiKeysReq;
import com.cyksj.model.request.ClaudeCodeCreditCardUseReq;
import com.cyksj.model.request.ClaudeCodeDelReq;
import com.cyksj.model.request.CreditResetReq;
import com.cyksj.model.request.codex.CodexUserPackageReq;
import com.cyksj.model.response.ClaudeCodeRewardDetailsResp;
import com.cyksj.model.response.CreditResetResp;
import com.cyksj.model.response.TimeRateConfigsResp;
import com.cyksj.model.response.claudecode.ClaudeCodeResp;
import com.cyksj.model.views.*;
import com.cyksj.redis.RedisService;
import com.cyksj.service.claude.ClaudeCodeService;
import com.cyksj.service.codex.CodexService;
import com.cyksj.service.user.UserBindRelationService;
import com.ejlchina.searcher.BeanSearcher;
import com.ejlchina.searcher.SearchResult;
import com.ejlchina.searcher.param.Operator;
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;

/**
 * 项目名: yhlxj11111111
 * 文件名: ClaudeCodeServiceImpl
 * 创建者: JavaZou
 * 创建时间:2025/8/8 10:55
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ClaudeCodeServiceImpl implements ClaudeCodeService {
	private final UserBindRelationService userBindRelationService;

	private final GroupsRelationMapper relationMapper;

	private final BeanSearcher beanSearcher;

	private final ClaudeCodeUserRenewExpiryRecordMapper claudeCodeUserRenewExpiryRecordMapper;

	private final ClaudeCodeUserMapper claudeCodeUserMapper;

	private final GoodsDonSkuMapper skuMapper;

	private final GroupsMapper groupsMapper;

	private final OrderDonMapper orderDonMapper;

	private final ClaudeCodeUserResetRecordMapper claudeCodeUserResetRecordMapper;

	private final ClaudeCodeUserCreditCardRecordMapper claudeCodeUserCreditCardRecordMapper;

	private final ClaudeCodeCreditCardMapper claudeCodeCreditCardMapper;

	private final UserMapper userMapper;

	private final DistributeWaitingSendPointsMapper distributeWaitingSendPointsMapper;

	private final DistributePointsExchangeMoneyMapper distributePointsExchangeMoneyMapper;

	private final GoodsDonMapper goodsDonMapper;

	private final ClaudeCodeDayResetRecordMapper claudeCodeDayResetRecordMapper;

	private final RedisService redisService;

	private final CodexService codexService;
	
	private final CodexUserMapper codexUserMapper;

	@Override
	public void generateOrUpdateClaudeCodeUserInfo(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 thisRelationCodeDayilyLimit = null;
		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
		if (claudeCodeUser != null) {
			thisRelationCodeDayilyLimit = claudeCodeUser.getClaudeDailyLimit();
		}
		Date expiryTime = relation.getExpiryTime();
		Integer claudeDailyLimit = sku.getClaudeDailyLimit();
		Integer claudeQuota = sku.getClaudeQuota();
		Long skuId = sku.getId();
		Boolean isUpgrade = false;
		Date renewExpiryTime = null;
		//若是续费升级 记录此时续费升级的过期时间
		if (!ObjectUtil.equal(thisCodeOriSkuId, skuId)) {
			//非车票原规格id 续费升级记录
			saveClaudeCodeRenewExpiryRecord(orderId, relationUserId, relationId, skuId);
			//是否需要修改当前claude code user 套餐等级
			if (thisRelationCodeDayilyLimit != null && thisRelationCodeDayilyLimit <= claudeDailyLimit) {
				if (sku.getDays() != null) {
					renewExpiryTime = DateUtil.offsetDay(DateTime.now(), sku.getDays());
				} else {
					renewExpiryTime = DateUtil.offsetMonth(DateTime.now(), sku.getMonths());
				}
				isUpgrade = true;
			}
		}
		generateOrUpdateClaudeCodeUser(relationUserId, relationId, claudeDailyLimit, claudeQuota, expiryTime, isUpgrade, orderId, skuId, renewExpiryTime, sku.getSpecVal(), userIdList);
		try {
			//获取最新的claude code user
			claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
			//生成claude code或更新用户套餐
			ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(relation.getUserId(), claudeCodeUser.getPlanName(), claudeCodeUser.getClaudeDailyLimit(), claudeCodeUser.getClaudeQuota(), claudeCodeUser.getExpiryTime(), claudeCodeUser.getRelationId(), sku);
			if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
				//重试更新code userInfo数据
				setClaudeCodeUserRetryUpdateInfo(relationId);
				return;
			}
			//清缓存
			if (orderType != null && orderType == 2) {
				invalidateUserCache(relationUserId);
			}
		} catch (Exception e) {
			log.error("生成或更新claude code用户：{}套餐skuId:{} 失败，error_info:{}", userId, skuId, StringUtil.getErrorText(e));
			//重试更新code userInfo数据
			setClaudeCodeUserRetryUpdateInfo(relationId);
		}
	}

	private void generateOrUpdateClaudeCodeUser(Long relationUserId, Long relationId, Integer claudeDailyLimit, Integer claudeQuota, Date expiryTime, Boolean isUpgrade, Long orderId, Long renewSkuId, Date renewExpiryTime, String planName, List<Long> userIdList) {
		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
		if (claudeCodeUser == null) {
			claudeCodeUser = new ClaudeCodeUser();
		}
		if (isUpgrade) {
			claudeCodeUser.setRenewOrderId(orderId);
			claudeCodeUser.setRenewSkuId(renewSkuId);
			claudeCodeUser.setRenewExpiryTime(renewExpiryTime);
			claudeCodeUser.setPlanName(planName);
			claudeCodeUser.setClaudeDailyLimit(claudeDailyLimit);
			claudeCodeUser.setClaudeQuota(claudeQuota);
		}
		claudeCodeUser.setUserId(relationUserId);
		claudeCodeUser.setRelationId(relationId);
		claudeCodeUser.setExpiryTime(expiryTime);
		if (claudeCodeUser.getId() == null) {
			claudeCodeUser.setPlanName(planName);
			claudeCodeUser.setClaudeDailyLimit(claudeDailyLimit);
			claudeCodeUser.setClaudeQuota(claudeQuota);
			//可重置次数
			Integer resetCount = claudeCodeUserResetRecordMapper.getUserResetCountByUserIds(userIdList);
			if (resetCount != null && resetCount > 0) {
				claudeCodeUser.setResetCount(resetCount);
			}
		}
		if (claudeCodeUser.getId() == null) {
			try {
				claudeCodeUserMapper.insert(claudeCodeUser);
			} catch (DuplicateKeyException e) {
				log.info("插入claude code user 重复");
			}
		} else claudeCodeUserMapper.updateById(claudeCodeUser);
	}

	@Override
	public ClaudeCodeResp createApiKeys(ClaudeCodeApiKeysReq req) throws Exception {
		Long userId = req.getUserId();
		if (checkClaudeCodeUser(userId)) {
			Long claudeCodeUserId = getClaudeCodeUserId(userId);
			Assert.notNull(claudeCodeUserId, "您的claude code账号已过期");
			String apiKeyUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", claudeCodeUserId);
			Map<String, Object> parmas = new HashMap<>();
			parmas.put("name", req.getName());
			Integer expiresDays = req.getExpiresDays();
			if (expiresDays != null) {
				parmas.put("expires_days", expiresDays);
			}
			ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(apiKeyUrl, Jsons.toJson(parmas));
			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
				throw BusinessRuntimeException.getInstance("创建失败");
			}
			return claudeCodeResp;
		}
		throw new BusinessRuntimeException("您还没有claudecode账号");
	}

	@Override
	public void deleteApiKeysById(ClaudeCodeDelReq delReq) throws Exception {
		Long userId = delReq.getUserId();
		Long keyId = delReq.getKeyId();
		if (checkClaudeCodeUser(userId)) {
			Long claudeCodeUserId = getClaudeCodeUserId(userId);
			String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/keys/%s/%s", claudeCodeUserId, keyId);
			HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
			String responseBody = execute.body();
			ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
				log.error("删除key失败：{}", claudeCodeResp.getMessage());
				throw BusinessRuntimeException.getInstance("删除失败");
			}
		}
	}

	@Override
	public List<ClaudeCodeUserApiKeysView> getUserApiKeys(long userId) throws Exception {
		Long claudeCodeUserId = getClaudeCodeUserId(userId);
		if (claudeCodeUserId != null) {
			String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", claudeCodeUserId);
			ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
			return Jsons.parseList(claudeCodeResp.getData(), ClaudeCodeUserApiKeysView.class);
		}
		return null;
	}

	@Override
	public ClaudeCodeResp getUserDashboard(Long userId) throws Exception {
		Long claudeCodeUserId = getClaudeCodeUserId(userId);
		if (claudeCodeUserId != null) {
			String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/claude/users/%s/dashboard", claudeCodeUserId);
			ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
			return claudeCodeResp;
		}
		return null;
	}

	@Override
	public ClaudeCodeResp getUserBalance(Long userId) throws Exception {
		Long claudeCodeUserId = getClaudeCodeUserId(userId);
		if (claudeCodeUserId != null) {
			String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/balance", claudeCodeUserId);
			ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
			return claudeCodeResp;
		}
		return null;
	}

	@Override
	public ClaudeCodeResp getCreditsAnalytics(Long userId, String start, String end, String tz, Integer page, Integer limit, String order, String type) throws Exception {
		Long claudeCodeUserId = getClaudeCodeUserId(userId);
		if (start == null) {
			DateTime now = DateTime.now();
			start = DateUtil.offsetDay(now, -1).toString();
			end = now.toString();
		}
		if (claudeCodeUserId != null) {
			String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/claude/users/%s/analytics?start=%s&end=%s&tz=%s&page=%s&limit=%s&order=%s&type=%s", claudeCodeUserId, start, end, tz, page, limit, order, type);
			ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
			return claudeCodeResp;
		}
		return null;
	}


	/**
	 * 用户缓存失效
	 */
	@Override
	public void invalidateUserCache(Long userId) {
		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/cache/invalidate/user/%s", userId);
		try {
			executeClaudeCodePostApi(url, null);
		} catch (Exception e) {

		}
	}

	@Override
	public ClaudeCodeUserInfoView getClaudeCodeUserSubsInfo(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.CLAUDE_CODE_GOODS_ID)
				.field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
				.build());
		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));
		CodexUser codexUser = null;
		CodexUserInfoView codexUserInfoView = null;
		//车票不存在
		if (groupsRelationView == null) {
			//套餐是否存在
			if (claudeCodeUser != null) {
				//清除用户套餐
				if (delUserPackages(claudeCodeUser.getUserId())) {
					claudeCodeUserMapper.deleteById(claudeCodeUser.getId());
					//codex
					codexUserMapper.delete(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, claudeCodeUser.getRelationId()).in(CodexUser::getUserId, userIdList));
				}
			}
			return null;
		}
		GoodsDonSku sku = null;
		if (claudeCodeUser == null) {
			OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
					.eq(OrderDon::getGoodsId, Constant.CLAUDE_CODE_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());
				generateOrUpdateClaudeCodeUserInfo(orderDon.getId(), orderDon.getRelationId(), orderDon.getUserId(), sku, orderDon.getOrderType());
				claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));
			} else {
				//试用车票
				Long skuId = groupsRelationView.getSkuId();
				sku = skuMapper.selectById(skuId);
				generateOrUpdateClaudeCodeUserInfo(null, groupsRelationView.getId(), groupsRelationView.getUserId(), sku, null);
				claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));
			}
		} else {
			claudeCodeUser.setExpiryTime(groupsRelationView.getExpiryTime());
			claudeCodeUserMapper.updateById(claudeCodeUser);
		}
		//续费升级
		if (claudeCodeUser.getRenewSkuId() != null) {
			sku = skuMapper.selectById(claudeCodeUser.getRenewSkuId());
		}
		if (sku == null) {
			sku = skuMapper.selectById(groupsRelationView.getSkuId());
		}
		//是否需要重试更新 cladueCode userInfo信息
		if (claudeCodeUser.getIsRetry()) {
			try {
				ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(claudeCodeUser.getUserId(), claudeCodeUser.getPlanName(), claudeCodeUser.getClaudeDailyLimit(), claudeCodeUser.getClaudeQuota(), claudeCodeUser.getExpiryTime(), claudeCodeUser.getRelationId(), sku);
				if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
					claudeCodeUser.setIsRetry(Boolean.TRUE);
					claudeCodeUserMapper.updateById(claudeCodeUser);
				} else {
					claudeCodeUser.setIsRetry(Boolean.FALSE);
					claudeCodeUserMapper.updateById(claudeCodeUser);
				}
			} catch (Exception e) {

			}
		}
		codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, claudeCodeUser.getRelationId()).in(CodexUser::getUserId, userIdList).last("limit 1"));
		if (codexUser == null) {
			//是否赠送codex
			if (sku.getIsCodex()) {
				CodexUserPackageReq codexPackageReq = CodexUserPackageReq.builder()
						.userId(claudeCodeUser.getUserId())
						.relationId(claudeCodeUser.getRelationId())
						.planName(sku.getCodexPlanName())
						.openaiDailyLimit(sku.getOpenaiDailyLimit())
						.openaiQuota(sku.getOpenaiQuota())
						.expiryTime(claudeCodeUser.getExpiryTime()).build();
				codexService.createOrUpdateUserPackage(codexPackageReq);
			}
		}
		return ClaudeCodeUserInfoView.builder()
				.planName(claudeCodeUser.getPlanName())
				.relationId(claudeCodeUser.getRelationId())
				.claudeDailyLimit(claudeCodeUser.getClaudeDailyLimit())
				.claudeQuota(claudeCodeUser.getClaudeQuota())
				.expiryTime(claudeCodeUser.getExpiryTime())
				.renewSkuId(Optional.ofNullable(claudeCodeUser.getRenewSkuId()).orElse(groupsRelationView.getSkuId()))
				.renewOrderId(claudeCodeUser.getRenewOrderId())
				.renewExpiryTime(claudeCodeUser.getRenewExpiryTime())
				.highestUsage(sku.getHighestUsage())
				.build();
	}

	public ClaudeCodeResp createOrUpdateClaudeCodeUserPackage(Long userId, String planName, Integer claudeDailyLimit, Integer claudeQuota, Date expiryTime, Long relationId, GoodsDonSku sku) throws Exception {
		Map<String, Object> parmas = new HashMap<>();
		parmas.put("plan_name", planName.replaceAll(";", ""));
		parmas.put("claude_daily_limit", claudeDailyLimit);
		parmas.put("claude_quota", claudeQuota);
		//服务类型
		parmas.put("service_type", "claude");
		if (sku.getIsCodex()) {
			parmas.put("openai_daily_limit", sku.getOpenaiDailyLimit());
			parmas.put("openai_quota", sku.getOpenaiQuota());
			//组合
			parmas.put("service_type", "combined");
		} else {
			parmas.put("openai_daily_limit", 0);
			parmas.put("openai_quota", 0);
			//单独 claude类型
			parmas.put("service_type", "claude");
		}
		parmas.put("expire_time", DateUtil.format(expiryTime, "yyyy-MM-dd HH:mm:ss"));
		String planUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", userId);
		ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(planUrl, Jsons.toJson(parmas));
		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
			log.info("用户claude code用户:{}套餐:{}创建或更新失败，info:{}", userId, planName, claudeCodeResp.getMessage());
		} else {
			//是否赠送codex
			if (sku.getIsCodex()) {
				CodexUserPackageReq codexPackageReq = CodexUserPackageReq.builder()
						.userId(userId)
						.relationId(relationId)
						.planName(sku.getCodexPlanName())
						.openaiDailyLimit(sku.getOpenaiDailyLimit())
						.openaiQuota(sku.getOpenaiQuota())
						.expiryTime(expiryTime).build();
				codexService.createOrUpdateUserPackage(codexPackageReq);
			} else {
				codexService.delCodexUser(userId, relationId);
			}
		}
		return claudeCodeResp;
	}


	/**
	 * 校验是否是claude code用户
	 * @param userId
	 * @return
	 */
	@Override
	public Boolean checkClaudeCodeUser(Long userId) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		Integer count = relationMapper.selectCountByGoodsId(userIdList, Constant.CLAUDE_CODE_GOODS_ID, DateTime.now());
		return count > 0;
	}

	@Override
	public void updateClaudeCodeUserPackageInfo(ClaudeCodeUser claudeCodeUser, Date expiryTime, GoodsDonSku sku) {
		try {
			ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(claudeCodeUser.getUserId(), claudeCodeUser.getPlanName(), claudeCodeUser.getClaudeDailyLimit(), claudeCodeUser.getClaudeQuota(), expiryTime, claudeCodeUser.getRelationId(), sku);
			if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
				//重试标记
				claudeCodeUser.setIsRetry(Boolean.TRUE);
				claudeCodeUserMapper.updateById(claudeCodeUser);
				return;
			}
			//刷新缓存
			invalidateUserCache(claudeCodeUser.getUserId());
		} catch (Exception e) {
			claudeCodeUser.setIsRetry(Boolean.TRUE);
			claudeCodeUserMapper.updateById(claudeCodeUser);
		}
	}

	@Override
	public Boolean delUserPackages(Long userId) {
		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan?service_type=claude", 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;
	}

	@Override
	public void handleClaudeCodeUserPackageSku(GroupsRelation relation, GoodsDonSku sku, Long orderId) {
		generateOrUpdateClaudeCodeUserInfo(orderId, relation.getId(), relation.getUserId(), sku, 2);
	}

	@Override
	public TimeRateConfigsResp getAllConfigs() {
		try {
			String url = Constant.CLAUDE_CODE_API_PREFIX + "api/time-multiplier/configs";
			ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
			return Jsons.parseObject(claudeCodeResp.getData(), TimeRateConfigsResp.class);
		} catch (Exception e) {
			log.error("获取时间倍率配置列表失败", e);
			throw BusinessRuntimeException.getInstance("获取时间倍率配置列表失败");
		}
	}

	@Override
	public CreditResetResp resetUserCredits(Long userId, CreditResetReq req) throws Exception {
		if (userId <= 0) {
			throw BusinessRuntimeException.getInstance("用户ID无效");
		}

		String url = Constant.CLAUDE_CODE_API_PREFIX + "api/users/" + userId + "/credits/reset";
		String body = req != null ? Jsons.toJson(req) : "{}";
		ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(url, body);
		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
			throw BusinessRuntimeException.getInstance("重置次数失败");
		}
		return Jsons.parseObject(claudeCodeResp.getData(), CreditResetResp.class);
	}

	/**
	 * 验证时间范围
	 */
	private void validateTimeRange(Integer startHour, Integer endHour) {
		if (startHour == null || endHour == null) {
			throw BusinessRuntimeException.getInstance("开始和结束小时不能为空");
		}
		if (startHour < 0 || startHour > 23) {
			throw BusinessRuntimeException.getInstance("开始小时必须在0-23之间");
		}
		if (endHour < 0 || endHour > 23) {
			throw BusinessRuntimeException.getInstance("结束小时必须在0-23之间");
		}
	}

	/**
	 * 获取claude code用户id
	 */
	public Long getClaudeCodeUserId(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.CLAUDE_CODE_GOODS_ID)
				.field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
				.build());
		if (groupsRelationView != null) {
			return groupsRelationView.getUserId();
		}
		return null;
	}

	/**
	 * claude code GET请求
	 */
	public ClaudeCodeResp executeClaudeCodeGetApi(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 (!Constant.SUCCESS.equals(resp.getMessage())) {
						log.error("claude code GET URL:{}接口返回msg：{}", url, resp.getMessage());
					}
					return resp;
				} catch (HttpException e) {
					return null;
				}
			});
		} catch (ExecutionException | RetryException e) {
			log.error("重试调用claude code GET请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
			throw BusinessRuntimeException.getInstance("接口请求失败");
		}
	}


	/**
	 * claude code Post请求
	 */
	public ClaudeCodeResp executeClaudeCodePostApi(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 (!Constant.SUCCESS.equals(resp.getMessage())) {
						log.error("claude code POST URL:{}接口返回msg：{}", url, resp.getMessage());
					}
					return resp;
				} catch (Exception e) {
					return null;
				}
			});
		} catch (ExecutionException | RetryException e) {
			log.info("重试调用claude code POST请求 url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
			throw BusinessRuntimeException.getInstance("接口请求失败");
		}
	}

	/**
	 * 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("接口请求失败");
		}
	}

	/**
	 * 记录claude code 续费升级的过期时间
	 */
	private void saveClaudeCodeRenewExpiryRecord(Long orderId, Long relationUserId, Long relationId, Long skuId) {
		ClaudeCodeUserRenewExpiryRecord renewExpiryRecord = new ClaudeCodeUserRenewExpiryRecord();
		renewExpiryRecord.setOrderId(orderId);
		renewExpiryRecord.setUserId(relationUserId);
		renewExpiryRecord.setRelationId(relationId);
		renewExpiryRecord.setRenewSkuId(skuId);
		claudeCodeUserRenewExpiryRecordMapper.insert(renewExpiryRecord);
	}

	/**
	 * claude code、codex user用户信息重试更新信息
	 */
	public void setClaudeCodeUserRetryUpdateInfo(Long relationId) {
		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
		if (claudeCodeUser != null) {
			claudeCodeUser.setIsRetry(Boolean.TRUE);
			claudeCodeUserMapper.updateById(claudeCodeUser);
		}

		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);
		}
	}

	public Retryer getApiRetryer(Integer sleepSecond, Integer attemptNum) {
		Retryer build = RetryerBuilder.newBuilder()
				.retryIfException()
				//运行时异常重试
				.retryIfRuntimeException()
				//false重试
				.retryIfResult(res -> res == null)
				//1s 间隔
				.withWaitStrategy(WaitStrategies.fixedWait(sleepSecond, TimeUnit.SECONDS))
				//停止策略 : 尝试请求3次
				.withStopStrategy(StopStrategies.stopAfterAttempt(attemptNum)).build();
		return build;
	}
	@Override
	@Transactional(rollbackFor = Throwable.class)
	public void useResetCount(Long userId) throws Exception {
		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) {
			throw new BusinessRuntimeException("用户未开通Claude Code服务");
		}

		Integer currentResetCount = claudeCodeUser.getResetCount();
		if (currentResetCount == null || currentResetCount <= 0) {
			throw BusinessRuntimeException.getInstance("可用重置次数为0");
		}

		claudeCodeUser.setResetCount(currentResetCount - 1);
		int updateResult = claudeCodeUserMapper.update(claudeCodeUser,
				Wrappers.lambdaUpdate(ClaudeCodeUser.class)
						.eq(ClaudeCodeUser::getId, claudeCodeUser.getId())
						.eq(ClaudeCodeUser::getResetCount, currentResetCount)
		);

		if (updateResult > 0) {
			log.info("用户{}成功使用重置次数，剩余次数：{}", userId, currentResetCount - 1);
			//重置用户次数
			CreditResetReq creditResetReq = new CreditResetReq();
			creditResetReq.setDescription("用户使用重置次数");
			//调用API重置用户次数
			resetUserCredits(claudeCodeUser.getUserId(), creditResetReq);

			ClaudeCodeUserResetRecord resetRecord = new ClaudeCodeUserResetRecord();
			resetRecord.setUserId(userId);
			resetRecord.setNum(-1);
			resetRecord.setResetReason("使用重置次数");
			claudeCodeUserResetRecordMapper.insert(resetRecord);

		} else {
			throw BusinessRuntimeException.getInstance("使用重置次数失败");
		}
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public void useCreditCard(ClaudeCodeCreditCardUseReq req) throws Exception {
		Long userId = req.getUserId();
		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) {
			throw new BusinessRuntimeException("用户未开通Claude Code服务");
		}

		ClaudeCodeCreditCard creditCard = claudeCodeCreditCardMapper.selectOne(
				Wrappers.lambdaQuery(ClaudeCodeCreditCard.class)
						.eq(ClaudeCodeCreditCard::getStatus, 0)
						.in(ClaudeCodeCreditCard::getUserId, userIdList)
						.last("limit 1")
		);

		if (creditCard == null) {
			throw new BusinessRuntimeException("无可用补充卡");
		}

		if (creditCard.getStatus() != 0) {
			if (creditCard.getStatus() == 1) {
				throw new BusinessRuntimeException("补充卡已被使用");
			} else if (creditCard.getStatus() == 2) {
				throw new BusinessRuntimeException("补充卡已过期");
			} else {
				throw new BusinessRuntimeException("补充卡状态异常");
			}
		}
		String cardNumber = creditCard.getCardNumber();

		if (creditCard.getExpiryTime() != null && creditCard.getExpiryTime().before(new Date())) {
			creditCard.setStatus(2);
			claudeCodeCreditCardMapper.updateById(creditCard);
			throw new BusinessRuntimeException("补充卡已过期");
		}

		ClaudeCodeResp dashboard = getUserDashboard(userId);
		JSONObject data = Jsons.parseObject(dashboard.getData(), JSONObject.class);
		Integer daily_remaining = data.getInt("daily_remaining");
		Integer daily_total = data.getInt("daily_total");
		//超出积分 异常
		if (daily_remaining + creditCard.getCreditAmount() > daily_total) {
			throw BusinessRuntimeException.getInstance("目前使用只能补充到{0}，建议您消耗更多额度后再补充使用", daily_total);
		}

		Integer beforeCodePoints = daily_remaining;
		Integer addCodePoints = creditCard.getCreditAmount();
		Integer afterCodePoints = beforeCodePoints + addCodePoints;

		creditCard.setStatus(1);
		creditCard.setUsedUserId(userId);
		creditCard.setUsedTime(new Date());
		int cardUpdateResult = claudeCodeCreditCardMapper.update(creditCard,
				Wrappers.lambdaUpdate(ClaudeCodeCreditCard.class)
						.eq(ClaudeCodeCreditCard::getId, creditCard.getId())
						.eq(ClaudeCodeCreditCard::getStatus, 0)
		);

		if (cardUpdateResult > 0) {
			ClaudeCodeUserCreditCardRecord creditCardRecord = new ClaudeCodeUserCreditCardRecord();
			creditCardRecord.setUserId(userId);
			creditCardRecord.setBeforeCodePoints(beforeCodePoints);
			creditCardRecord.setAddCodePoints(addCodePoints);
			creditCardRecord.setAfterCodePoints(afterCodePoints);
			creditCardRecord.setCardNumber(cardNumber);
			//使用一次
			creditCardRecord.setNum(-1);
			creditCardRecord.setUseReason("使用补充卡");

			claudeCodeUserCreditCardRecordMapper.insert(creditCardRecord);

			log.info("用户{}成功使用补充卡{}，增加{}预算", userId, cardNumber, addCodePoints);
			//调用API调整用户积分
			adjClaudeCodeUserPoints(claudeCodeUser.getUserId(), creditCard.getCreditAmount(), "adjustment", "用户使用补充卡");
		} else {
			throw new BusinessRuntimeException("补充卡使用失败，请重试");
		}
	}

	@Override
	public SearchResult<ClaudeCodeUserResetRecordView> getUserResetRecords(Long userId, Integer page, Integer limit) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);

		return beanSearcher.search(ClaudeCodeUserResetRecordView.class, MapUtils.builder()
			.field(ClaudeCodeUserResetRecordView::getUserId, userIdList).op(Operator.InList)
			.page(page, limit)
			.orderBy(ClaudeCodeUserResetRecordView::getCreatedTime).desc()
			.build());
	}

	@Override
	public SearchResult<ClaudeCodeUserCreditCardRecordView> getUserCreditCardRecords(Long userId, Integer page, Integer limit) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);

		return beanSearcher.search(ClaudeCodeUserCreditCardRecordView.class, MapUtils.builder()
			.field(ClaudeCodeUserCreditCardRecordView::getUserId, userIdList).op(Operator.InList)
			.page(page, limit)
			.orderBy(ClaudeCodeUserCreditCardRecordView::getCreatedTime).desc()
			.build());
	}

	@Override
	public ClaudeCodeRewardDetailsResp getUserRewardDetails(Long userId, Boolean general) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);

		ClaudeCodeRewardDetailsResp response = new ClaudeCodeRewardDetailsResp();

		// 获取用户Claude Code信息
		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
				Wrappers.lambdaQuery(ClaudeCodeUser.class)
						.in(ClaudeCodeUser::getUserId, userIdList)
						.last("limit 1")
		);

		// 设置可重置次数
		if (claudeCodeUser != null) {
			Integer resetCount = claudeCodeUser.getResetCount();
			response.setResetCount(resetCount != null ? resetCount : 0);
		} else {
			response.setResetCount(0);
		}

		// 获取可用补充卡数量
		Integer availableCreditCards = claudeCodeCreditCardMapper.selectCount(
				Wrappers.lambdaQuery(ClaudeCodeCreditCard.class)
						.eq(ClaudeCodeCreditCard::getStatus, 0)
						.in(ClaudeCodeCreditCard::getUserId, userIdList)
						.isNull(ClaudeCodeCreditCard::getUsedUserId)
		);
		response.setAvailableCreditCards(availableCreditCards != null ? availableCreditCards : 0);

		//是否是普通推广
		if (general != null && general) {
			//提现门槛
			DistributePointsExchangeMoney distributePointsExchangeMoney = distributePointsExchangeMoneyMapper.selectOne(Wrappers.lambdaQuery(DistributePointsExchangeMoney.class).last("limit 1"));
			response.setThresholdMoney(BigDecimal.valueOf(distributePointsExchangeMoney.getMinPoints()).divide(BigDecimal.valueOf(distributePointsExchangeMoney.getPoints())).multiply(distributePointsExchangeMoney.getMoney()));

			// 获取分销相关数据
			try {
				User user = userMapper.selectById(userId);
				List<DistributeWaitingSendPoints> distributeWaitingSendPoints = distributeWaitingSendPointsMapper.selectList(Wrappers.lambdaQuery(DistributeWaitingSendPoints.class).eq(DistributeWaitingSendPoints::getSendStatus, DistributeWaitingSendPoints.Status.waiting).eq(DistributeWaitingSendPoints::getSharedId, userId).select(DistributeWaitingSendPoints::getPoints));
				BigDecimal waitingPoints = BigDecimal.ZERO;
				if (!distributeWaitingSendPoints.isEmpty()) {
					Optional<BigDecimal> points = distributeWaitingSendPoints.stream().map(DistributeWaitingSendPoints::getPoints).reduce(BigDecimal::add);
					if (points.isPresent()) {
						waitingPoints = points.get();
					}
				}
				GoodsDon goodsDon = goodsDonMapper.selectById(Constant.CLAUDE_CODE_GOODS_ID);
				//cc 分销平台比例
				if (goodsDon != null) {
					response.setRate(goodsDon.getRate());
				}

				if (user.getPoints().compareTo(BigDecimal.ZERO) <= 0 && waitingPoints.compareTo(BigDecimal.ZERO) <= 0) {
					response.setGotMoney(BigDecimal.ZERO);
					response.setWaitingMoney(BigDecimal.ZERO);
				} else {
					BigDecimal points = BigDecimal.valueOf(distributePointsExchangeMoney.getPoints());
					BigDecimal money = distributePointsExchangeMoney.getMoney();
					BigDecimal oneHundred = BigDecimal.valueOf(100);
					if (user.getPoints().compareTo(BigDecimal.ZERO) >= 0) {
						response.setGotMoney(user.getPoints().divide(points).multiply(money).divide(oneHundred, 2, RoundingMode.HALF_DOWN));
					}
					if (user.getPoints().compareTo(BigDecimal.ZERO) >= 0) {
						response.setWaitingMoney(waitingPoints.divide(points).multiply(money).divide(oneHundred, 2, RoundingMode.DOWN));
					}
				}

			} catch (Exception e) {
				log.warn("获取用户{}分销数据异常", userId, e);
				// 设置默认值
				response.setGotMoney(BigDecimal.ZERO);
				response.setWaitingMoney(BigDecimal.ZERO);
			}
		}
		return response;
	}

	@Override
	public void sendCreditCard(Long orderId, Long userId, Integer points, String cardNumber, String remark) {
		ClaudeCodeCreditCard creditCard = new ClaudeCodeCreditCard();
		creditCard.setUserId(userId);
		creditCard.setOrderId(orderId);
		creditCard.setCardNumber(cardNumber);
		creditCard.setCreditAmount(points);
		creditCard.setRemark(remark);
		claudeCodeCreditCardMapper.insert(creditCard);

		//补充卡明细
		ClaudeCodeUserCreditCardRecord creditCardRecord = new ClaudeCodeUserCreditCardRecord();
		creditCardRecord.setUserId(userId);
		creditCardRecord.setCardNumber(cardNumber);
		creditCardRecord.setUseReason(remark);
		creditCardRecord.setNum(1);
		creditCardRecord.setAddCodePoints(points);
		claudeCodeUserCreditCardRecordMapper.insert(creditCardRecord);
	}

	@Override
	public void adjUserRestNum(Long orderId, Long userId, Integer num, String remark) {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);

		// 获取用户Claude Code信息
		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
				Wrappers.lambdaQuery(ClaudeCodeUser.class)
						.in(ClaudeCodeUser::getUserId, userIdList)
						.last("limit 1")
		);
		if (claudeCodeUser == null) {
			log.info("claude code user不存在");
			return;
		}
		Integer resetCount = claudeCodeUser.getResetCount();
		claudeCodeUser.setResetCount(resetCount + num);
		if (claudeCodeUser.getResetCount() < 0) {
			return;
		}
		int update = 0;
		while (update == 0) {
			update = claudeCodeUserMapper.update(claudeCodeUser, Wrappers.lambdaUpdate(ClaudeCodeUser.class).eq(ClaudeCodeUser::getUserId, claudeCodeUser.getUserId()).eq(ClaudeCodeUser::getResetCount, resetCount));
			if (update == 0) {
				claudeCodeUser = claudeCodeUserMapper.selectOne(
						Wrappers.lambdaQuery(ClaudeCodeUser.class)
								.in(ClaudeCodeUser::getUserId, userIdList)
								.last("limit 1")
				);
				if (claudeCodeUser == null) {
					break;
				}
				resetCount = claudeCodeUser.getResetCount();
				claudeCodeUser.setResetCount(resetCount + num);
				if (claudeCodeUser.getResetCount() < 0) {
					break;
				}
			}
			//记录获取重置次数记录
			ClaudeCodeUserResetRecord resetRecord = new ClaudeCodeUserResetRecord();
			resetRecord.setOrderId(orderId);
			resetRecord.setUserId(userId);
			resetRecord.setResetReason(remark);
			resetRecord.setNum(num);
			claudeCodeUserResetRecordMapper.insert(resetRecord);
		}
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public void useDayResetCount(Long userId) throws Exception {
		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
		// 获取用户Claude Code信息
		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
				Wrappers.lambdaQuery(ClaudeCodeUser.class)
						.in(ClaudeCodeUser::getUserId, userIdList)
						.last("limit 1")
		);
		if (claudeCodeUser == null) {
			log.info("claude code user不存在");
			return;
		}
		//非标准版、专业版 不给使用
		if (claudeCodeUser.getClaudeDailyLimit() < 5000) {
			return;
		}
		Integer selectCount = claudeCodeDayResetRecordMapper.selectCount(Wrappers.lambdaQuery(ClaudeCodeDayResetRecord.class).in(ClaudeCodeDayResetRecord::getUserId, userIdList).gt(ClaudeCodeDayResetRecord::getCreatedTime, DateUtil.beginOfDay(DateTime.now())));
		//今日使用为0
		if (selectCount == 0) {
			String idxKey = "cc:uid:" + userId;
			try {
				if (redisService.setNx(idxKey, userId, 5l)) {
					//重置用户次数
					CreditResetReq creditResetReq = new CreditResetReq();
					creditResetReq.setDescription("用户使用每日重置");
					//调用API重置用户次数
					resetUserCredits(claudeCodeUser.getUserId(), creditResetReq);

					ClaudeCodeDayResetRecord claudeCodeDayResetRecord = new ClaudeCodeDayResetRecord();
					claudeCodeDayResetRecord.setUserId(userId);
					claudeCodeDayResetRecord.setRelationId(claudeCodeUser.getRelationId());
					claudeCodeDayResetRecordMapper.insert(claudeCodeDayResetRecord);
				}
			} finally {
				if (redisService.hasKey(idxKey)) {
					redisService.del(idxKey);
				}
			}
		}
	}

	@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.CLAUDE_CODE_GOODS_ID)
				.field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
				.build());
		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));
		//车票不存在
		if (groupsRelationView == null) {
			//套餐是否存在
			if (claudeCodeUser != null) {
				//清除用户套餐
				if (delUserPackages(claudeCodeUser.getUserId())) {
					claudeCodeUserMapper.deleteById(claudeCodeUser.getId());
				}
			}
			return false;
		}
		return true;
	}

	private void adjClaudeCodeUserPoints(Long userId, Integer points, String type, String description) throws Exception {
		String apiKeyUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/credits/adjust", userId);
		Map<String, Object> parmas = new HashMap<>();
		parmas.put("amount", points);
		parmas.put("type", type);
		parmas.put("description", description);
		ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(apiKeyUrl, Jsons.toJson(parmas));
		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
			throw BusinessRuntimeException.getInstance("使用补充卡失败");
		}
	}

	/**
	 * 更新重试codexUser info
	 */
	private void updateCodexUserIfTry(CodexUser codexUser) {
		if (codexUser.getIsRetry()) {
			try {
				ClaudeCodeResp codeUserPackage = codexService.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) {

			}
		}
	}
}
