package com.cyksj.service.chatgpt.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
import com.cyksj.common.util.StringUtil;
import com.cyksj.mapper.*;
import com.cyksj.model.entity.*;
import com.cyksj.model.request.gpt.ConversationRequest;
import com.cyksj.model.response.ConversationLimitResponse;
import com.cyksj.model.views.ChatGptUserConversationRecordHistoryView;
import com.cyksj.model.views.ChatGptUserView;
import com.cyksj.model.views.ChatgptCarInfoView;
import com.cyksj.redis.RedisService;
import com.cyksj.service.chatgpt.ChatGptAccountService;
import com.cyksj.service.user.UserBindRelationService;
import com.ejlchina.searcher.BeanSearcher;
import com.ejlchina.searcher.SearchResult;
import com.ejlchina.searcher.util.MapUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.imageio.stream.FileImageOutputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chan
 * @date 2024/3/19 11:01
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ChatGptAccountServiceImpl implements ChatGptAccountService {

    @Value("${chatgpt.domain}")
    private String GPT_DOMAIN;

    @Value("${chatgpt.car.domain}")
    private String CAR_GPT_DOMAIN;

    private static final String GPT_PROXY = "https://chat-chan-87jztgkf257d.xyhelper.net";

    private static final int MAX_REQUESTS = 40; // 3小时内最大请求次数

    private static final long WINDOW_SIZE = 3 * 60 * 60; // 3小时窗口的秒数

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

    private final RedisService redisService;

    private final ChatgptUserMapper chatgptUserMapper;

    private final ChatgptSessionMapper chatgptSessionMapper;

    private final GroupsRelationMapper groupsRelationMapper;

    private final GroupsMapper groupsMapper;

    private final GoodsDonSkuMapper skuMapper;

    private final UserMapper userMapper;

    private final UserBindRelationService userBindRelationService;

    private final ChatgptUserConversationRecordMapper chatgptUserConversationRecordMapper;

    private final ChatgptUserConversationMapper chatgptUserConversationMapper;

    private final AccountMapper accountMapper;

    private final BeanSearcher beanSearcher;

    private final ChatgptUserTokenPrepareMapper chatgptUserTokenPrepareMapper;

    private final ChatgptUserCarUsedRecordMapper chatgptUserCarUsedRecordMapper;

    @Override
    public String addAccount(Account account) {
        if (isAccountExists(account)) {
            throw BusinessRuntimeException.getInstance("镜像服务该账号已存在.");
        }

        String refreshToken = "";
        String officialSession = "";
        try {
            JSONObject loginResult = getLoginResult(account);
            if (StringUtils.isBlank(loginResult.getStr("accessToken"))) {
                throw BusinessRuntimeException.getInstance(loginResult.getStr("detail"));
            }
            refreshToken = loginResult.getStr("refresh_token");
            officialSession = loginResult.toString();
        } catch (Exception e) {
            throw BusinessRuntimeException.getInstance("登录获取token错误 error:" + e.getMessage());
        }

        createChatgptSession(account, officialSession);

        return refreshToken;
    }

    @Override
    public String getGptSession(String account, String password) {
        String officialSession = "";
        try {
            Account at = new Account();
            at.setAccount(account);
            at.setPassword(password);
            JSONObject loginResult = getLoginResult(at);
            if (StringUtils.isBlank(loginResult.getStr("accessToken"))) {
                throw BusinessRuntimeException.getInstance(loginResult.getStr("detail"));
            }
            officialSession = loginResult.toString();
        } catch (Exception e) {
            throw BusinessRuntimeException.getInstance("登录获取token错误 error:" + e.getMessage());
        }
        return officialSession;
    }

    /**
     * 判断账号是否存在
     *
     * @param account 账号
     * @return 是否存在
     */
    private boolean isAccountExists(Account account) {
        Integer count = chatgptSessionMapper.selectCount(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getEmail, account.getAccount()));
        return count > 0;
    }

    /**
     * 获取登录结果
     *
     * @param account
     * @return
     * @throws Exception
     */
    private JSONObject getLoginResult(Account account) throws Exception {
        HttpRequest request = new HttpRequest(GPT_PROXY + "/getsession");
        request.form("username", account.getAccount());
        request.form("password", account.getPassword());
        request.header("Content-Type", "application/x-www-form-urlencoded");
        HttpResponse execute = request.method(Method.POST).execute();
        return new JSONObject(execute.body());
    }

    /**
     * 创建chatgptSession
     *
     * @param account
     * @param officialSession
     */
    private void createChatgptSession(Account account, String officialSession) {
        ChatgptSession chatgptSession = new ChatgptSession();
        chatgptSession.setOfficialSession(officialSession);
        chatgptSession.setEmail(account.getAccount());
        chatgptSession.setPassword(account.getPassword());
        chatgptSession.setIsPlus(1);
        chatgptSession.setAccountId(account.getId());
        chatgptSession.setStatus(1);
        chatgptSessionMapper.insert(chatgptSession);
    }

    /**
     * 更新账号
     *
     * @param account
     */
    @Override
    public void upAccount(Account account) {
        ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getEmail, account.getAccount()));
        if (chatgptSession != null) {
            if (StringUtils.isNotBlank(account.getGptRefreshToken())) {
                chatgptSession.setOfficialSession(account.getGptRefreshToken());
            }
            chatgptSession.setEmail(account.getAccount());
            chatgptSession.setPassword(account.getPassword());
            chatgptSession.setIsPlus(1);
            chatgptSession.setAccountId(account.getId());
            chatgptSession.setStatus(1);
            chatgptSessionMapper.updateById(chatgptSession);
        }
    }

    /**
     * 获取登录url
     *
     * @param userId
     * @param relationId
     * @return
     */
    @Override
    public String getLoginUrl(Long userId, Long relationId) {
        GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
        GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
        GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
        log.info("用户:{},所在车次:{},座位id:{},在{}获取跳转GPT镜像的登录url", userId, groupsTrips.getId(), relationId, DateTime.now());

        if (goodsDonSku != null && goodsDonSku.getIsMirror()) {
            ChatgptUser chatgptUser = getChatgptUser(userId, relationId, groupsRelation, groupsTrips, goodsDonSku);
            if (214610L == relationId) {
                return "https://cdn.galaxydvd.com/login_token?access_token=" + chatgptUser.getUserToken();
            }
            return GPT_DOMAIN + "/login_token?access_token=" + chatgptUser.getUserToken();
        } else {
            throw BusinessRuntimeException.getInstance("服务器出了点问题");
        }
    }

    /**
     * 获取车队登录url
     *
     * @param userId
     * @param carId
     * @return
     */
    @Override
    public String getCarLoginUrl(Long userId, Long relationId, String carId) {
        GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
        GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
        GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
        if (goodsDonSku != null && goodsDonSku.getIsMirror() && goodsDonSku.getIsCar()) {
            ChatgptUser chatgptUser = getChatgptCarUser(userId, relationId, groupsRelation, goodsDonSku);
            String DOMAIN = "https://chat.galaxydvd.com";
            log.info("domain:{}，用户:{},所在车次:{},座位id:{},在{}获取跳转GPT镜像的登录url", DOMAIN, userId, groupsTrips.getId(), relationId, DateTime.now());
            return DOMAIN + "/auth/logintoken?carid=" + carId + "&usertoken=" + chatgptUser.getUserToken();
        } else {
            throw BusinessRuntimeException.getInstance("服务器出了点问题");
        }
    }
    /**
     * 根据userToken获取车队登录url
     */
    @Override
    public String getCarLoginUrlWithToken(String userToken, String carId) {
        ChatgptUser chatgptUser = getCarChatGptUserWithToken(userToken);
        if (chatgptUser != null) {
            String DOMAIN = "https://chat.galaxydvd.com";
            log.info("domain:{}，渠道用户:{},在{}获取跳转GPT镜像的登录url", DOMAIN, userToken, DateTime.now());
            return DOMAIN + "/auth/logintoken?carid=" + carId + "&usertoken=" + chatgptUser.getUserToken();
        } else {
            throw BusinessRuntimeException.getInstance("服务出了点问题");
        }
    }

    /**
     * 获取车位信息
     *
     * @param userId
     * @param relationId
     * @return
     */
    private GroupsRelation getGroupsRelation(Long userId, Long relationId) {
        List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
        GroupsRelation groupsRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).in(GroupsRelation::getUserId, userIdList).eq(GroupsRelation::getId, relationId));
        if (groupsRelation == null) {
            throw BusinessRuntimeException.getInstance("车票不存在");
        }
        return groupsRelation;
    }

    /**
     * 获取车队信息
     *
     * @param groupsRelation
     * @return
     */
    private GroupsTrips getGroupsTrips(GroupsRelation groupsRelation) {
        GroupsTrips groupsTrips = groupsMapper.selectById(groupsRelation.getGroupsId());
        if (groupsTrips == null) {
            throw BusinessRuntimeException.getInstance("车队异常");
        }
        return groupsTrips;
    }

    private ChatgptUser getChatgptUser(Long userId, Long relationId, GroupsRelation groupsRelation, GroupsTrips groupsTrips, GoodsDonSku goodsDonSku) {
        ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getRelationId, relationId));
        User user = userMapper.selectById(userId);
        if (chatgptUser == null) {
            chatgptUser = createChatgptUser(groupsRelation, groupsTrips, user, goodsDonSku);
        } else {
            updateChatgptUser(groupsRelation, user, chatgptUser);
        }
        return chatgptUser;
    }

    private ChatgptUser getChatgptCarUser(Long userId, Long relationId, GroupsRelation groupsRelation, GoodsDonSku goodsDonSku) {
        ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getRelationId, relationId));
        User user = userMapper.selectById(userId);
        if (chatgptUser == null) {
            chatgptUser = createChatgptUser(groupsRelation, null, user, goodsDonSku);
        } else {
            updateChatgptUser(groupsRelation, user, chatgptUser);
        }
        return chatgptUser;
    }

    /**
     * 创建chatgptUser
     */
    private synchronized ChatgptUser createChatgptUser(GroupsRelation groupsRelation, GroupsTrips groupsTrips, User user, GoodsDonSku goodsDonSku) {
        ChatgptUser chatgptUser = new ChatgptUser();
        if (!goodsDonSku.getIsCar()) {
            ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getAccountId, groupsTrips.getAccountId()));
            if (chatgptSession == null) {

                Account account = accountMapper.selectById(groupsTrips.getAccountId());
                String officialSession = "";
                try {
                    JSONObject loginResult = getLoginResult(account);
                    if (StringUtils.isBlank(loginResult.getStr("accessToken"))) {
                        throw BusinessRuntimeException.getInstance(loginResult.getStr("detail"));
                    }
                    officialSession = loginResult.toString();
                } catch (Exception e) {
                    throw BusinessRuntimeException.getInstance("配置账号错误 msg: " + e.getMessage());
                }

                createChatgptSession(account, officialSession);
                chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getAccountId, groupsTrips.getAccountId()));

            }
            chatgptUser.setSessionId(chatgptSession.getId());
        }
        if (goodsDonSku.getIsCar()) {
            chatgptUser.setIsCar(true);
            chatgptUser.setLimitNum(goodsDonSku.getGptLimitNum());
            chatgptUser.setLimitTime(goodsDonSku.getGptLimitTime());
        }
        try {
            chatgptUser.setExpireTime(groupsRelation.getExpiryTime());
            chatgptUser.setIsPlus(1);
            chatgptUser.setName(user.getNickname());
            chatgptUser.setImg(getWxImg(user.getHeadimgurl(), user));
            chatgptUser.setRelationId(groupsRelation.getId());
            chatgptUser.setUserToken(UUID.randomUUID().toString());
            chatgptUserMapper.insert(chatgptUser);
        } catch (DuplicateKeyException e) {
            log.error("重复插入镜像用户:{}token,errmsg:{}", user.getNickname(), StringUtil.getErrorText(e));
        }
        return chatgptUser;
    }

    /**
     * 创建chatgptUser 无需车队
     */
    public ChatgptUser generateChatGptUserUnderPrepare(ChatgptUserTokenPrepare prepare) {
        ChatgptUser chatgptUser = new ChatgptUser();
        GoodsDonSku goodsDonSku = skuMapper.selectById(prepare.getSkuId());
        if (goodsDonSku == null) {
            throw BusinessRuntimeException.getInstance("车队规格不存在,请联系客服..");
        }
        if (goodsDonSku.getIsCar()) {
            chatgptUser.setIsCar(true);
            chatgptUser.setLimitNum(goodsDonSku.getGptLimitNum());
            chatgptUser.setLimitTime(goodsDonSku.getGptLimitTime());
        }
        try {
            chatgptUser.setExpireTime(DateUtil.offsetMonth(DateTime.now(), goodsDonSku.getMonths()));
            chatgptUser.setIsPlus(1);
            chatgptUser.setName(prepare.getName());
            chatgptUser.setImg(prepare.getImg());
            chatgptUser.setUserToken(prepare.getUserToken());
            chatgptUserMapper.insert(chatgptUser);

            prepare.setStatus(true);
            chatgptUserTokenPrepareMapper.updateById(prepare);
            log.info("用户激活userToken:{}成功", prepare.getUserToken());
        } catch (DuplicateKeyException e) {
            log.error("重复插入镜像车队用户:{}token,errmsg:{}" + chatgptUser.getId(), StringUtil.getErrorText(e));
        }
        return chatgptUser;
    }

    private void updateChatgptUser(GroupsRelation groupsRelation, User user, ChatgptUser chatgptUser) {
        chatgptUser.setName(user.getNickname());
        chatgptUser.setImg(getWxImg(user.getHeadimgurl(), user));
        chatgptUser.setExpireTime(groupsRelation.getExpiryTime());
        chatgptUserMapper.updateById(chatgptUser);
    }

    /**
     * 更换wx头像至oss
     */
    private String getWxImg(String headimgurl, User user) {
        if (headimgurl.contains("thirdwx.qlogo.cn")) {
            try {
                byte[] body = HttpUtil.downloadBytes(headimgurl);
                Path tempFile = Files.createTempFile("wxheadimg-" + user.getId(), ".jpeg");
                try (FileImageOutputStream imageOutput = new FileImageOutputStream(tempFile.toFile())) {
                    imageOutput.write(body, 0, body.length);
                }
                Map<String, Object> paramMap = new HashMap<>();
                paramMap.put("file", tempFile.toFile());
                JSONObject result = JSONUtil.parseObj(HttpUtil.post("https://files.liuliangbang.vip/pic/ups", paramMap));
                return result.getJSONObject("value").getJSONArray("saved").getJSONObject(0).getJSONObject("info").getStr("cdnUrl");
            } catch (Exception ex) {
                log.error("上传微信头像错误！msg:{}", StringUtil.getErrorText(ex));
                return "./avatars.png";
            }
        } else {
            return user.getHeadimgurl();
        }
    }

    @Override
    public ChatgptUser findByUserTokenAndExpireTimeAfter(String userToken, LocalDateTime now) {
        return chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken).gt(ChatgptUser::getExpireTime, now));
    }

    @Override
    public void saveConversationRecord(String userToken, ConversationRequest conversationRequest) {
        LambdaQueryWrapper<ChatgptSession> wrapper = Wrappers.lambdaQuery(ChatgptSession.class);
        ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken));
        if (StringUtils.isNotBlank(conversationRequest.getCarId())) {
            wrapper.eq(ChatgptSession::getCarId, conversationRequest.getCarId());
        } else {
            if (chatgptUser.getSessionId() != null) {
                wrapper.eq(ChatgptSession::getId, chatgptUser.getSessionId());
            }
        }
        ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(wrapper);
        ChatgptUserConversationRecord chatgptUserConversationRecord = new ChatgptUserConversationRecord();
        chatgptUserConversationRecord.setUserToken(userToken);
        chatgptUserConversationRecord.setCarId(chatgptSession.getCarId());
        chatgptUserConversationRecord.setCarName(chatgptSession.getCarName());
        if (StringUtils.isBlank(conversationRequest.getConversation_id())) {
            chatgptUserConversationRecord.setMessageId(conversationRequest.getMessages().get(0).getId());
        } else {
            chatgptUserConversationRecord.setConversationId(conversationRequest.getConversation_id());
        }

        chatgptUserConversationRecord.setModel(conversationRequest.getModel());
        chatgptUserConversationRecordMapper.insert(chatgptUserConversationRecord);

        if(!"text-davinci-002-render-sha".equals(conversationRequest.getModel())){
            String key = RedisService.key.CHATGPT_CONVERSATION_LIMIT.getName() + ":" + userToken;
            long currentTimeMillis = System.currentTimeMillis();

            redisService.del();
            if(redisService.hasKey("chatgpt:team:clears_in:" + chatgptSession.getCarId())){
                redisService.del("chatgpt:team:clears_in:" + chatgptSession.getCarId());
            }
            if (redisService.hasKey("chatgpt:clears_in:" + chatgptSession.getCarId())) {
                redisService.del("chatgpt:clears_in:" + chatgptSession.getCarId());
            }

            // 如果未超过限制，记录当前请求的时间戳
            redisService.zAdd(key, currentTimeMillis, currentTimeMillis);
            // 设置ZSet的过期时间，窗口大小加上一段冗余时间
            redisService.expire(key, (chatgptUser.getLimitTime() * 60 * 60) + 20);
        }

        if (StringUtils.isNotBlank(chatgptSession.getCarId())) {
            updateExperienceAndScore(chatgptSession.getCarId(), !"text-davinci-002-render-sha".equals(conversationRequest.getModel()), System.currentTimeMillis());
        }

    }


    @Override
    public ConversationLimitResponse conversationLimit(String userToken, String model, String carId, ChatgptUser chatgptUser, Boolean isCar) {
        ConversationLimitResponse conversationLimitResponse = new ConversationLimitResponse();
        conversationLimitResponse.setLimited(false);
        if (!"text-davinci-002-render-sha".equals(model)) {
            //如果不为车队 直接返回
            if (chatgptUser.getIsCar()) {
                conversationLimitResponse = isConversationAllowed(userToken, chatgptUser.getLimitNum(), chatgptUser.getLimitTime());
            }
        }

        return conversationLimitResponse;
    }


    /**
     * 检查是否允许进行进行提问
     *
     * @param userToken 用户token
     * @return true 如果允许请求，false 如果请求被限制
     */
    public ConversationLimitResponse isConversationAllowed(String userToken, int limit, Long limitTime) {
        String key = RedisService.key.CHATGPT_CONVERSATION_LIMIT.getName() + ":" + userToken;
        long currentTimeMillis = System.currentTimeMillis();
        long windowStartMillis = currentTimeMillis - (limitTime * 60 * 60) * 1000;
        ConversationLimitResponse conversationLimitResponse = new ConversationLimitResponse();
        // 清除时间窗口之前的请求记录
        redisService.zRemoveRangeByScore(key, 0, windowStartMillis);

        Long currentSize = redisService.zCard(key);
        if (currentSize != null && currentSize >= limit) {
            // 如果当前请求次数超过限制，则拒绝请求
            Set<Object> times = redisService.zRangeByScore(key, 0, currentTimeMillis, 0, 1);
            Long oldestTime = (Long) times.stream().findFirst().orElse(null);
            if (oldestTime != null) {
                // 下一次可用时间是最早请求时间之后的3小时
                long nextAvailableTime = oldestTime + (limitTime * 60 * 60 * 1000);
                conversationLimitResponse.setNextAvailableTime(nextAvailableTime);
            }
            conversationLimitResponse.setLimited(true);
            //用户次数使用限制
            ChatgptUserCarUsedRecord chatgptUserCarUsedRecord = new ChatgptUserCarUsedRecord();
            chatgptUserCarUsedRecord.setUserToken(userToken);
            chatgptUserCarUsedRecord.setIsUserLimit(true);
            chatgptUserCarUsedRecordMapper.insert(chatgptUserCarUsedRecord);
            return conversationLimitResponse;
        } else {
            conversationLimitResponse.setLimited(false);
            return conversationLimitResponse;
        }
    }


    /**
     * 获取指定用户ID在滑动窗口内的提问次数
     *
     * @param userToken 用户token
     * @return 滑动窗口内的请求次数
     */
    @Override
    public Long getConversationCount(String userToken, Long limitTime) {
        String key = RedisService.key.CHATGPT_CONVERSATION_LIMIT.getName() + ":" + userToken;
        long currentTimeMillis = System.currentTimeMillis();
        long windowStartMillis = currentTimeMillis - (limitTime * 60 * 60) * 1000;

        // 清除时间窗口之前的请求记录（可选，根据需要决定是否在此处清理过期记录）
        redisService.zRemoveRangeByScore(key, 0, windowStartMillis);

        // 获取当前窗口内的请求次数
        Long currentSize = redisService.zCard(key);
        return currentSize != null ? currentSize : 0L;
    }

    /**
     * 获取指定车队ID在滑动窗口内的提问次数
     *
     * @param carId 车队ID
     * @return 滑动窗口内的请求次数
     */
    private Long getCarConversationCount(String carId, Long limitTime) {
        // 定义键名
        String key = RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId;
        long timestamp = System.currentTimeMillis();

        long windowStartMillis = timestamp - (limitTime * 60 * 60 * 1000);

        // 清除时间窗口之前的请求记录（可选，根据需要决定是否在此处清理过期记录）
        redisService.zRemoveRangeByScore(key, 0, windowStartMillis);

        // 获取当前窗口内的请求次数
        Long currentSize = redisService.zCard(key);
        return currentSize != null ? currentSize : 0L;
    }

    @Override
    public ChatgptSession checkSession(String carId) {
        ChatgptSession chatgptSession = chatgptSessionMapper.selectOne(Wrappers.lambdaQuery(ChatgptSession.class).eq(ChatgptSession::getCarId, carId).eq(ChatgptSession::getIsCar, true).last(" limit 1"));
        if (chatgptSession == null) {
            throw BusinessRuntimeException.getInstance("车队不存在");
        }
        return chatgptSession;
    }


    private Long carOaiLimit(String carId, Boolean isTeam) {
        if(isTeam && redisService.hasKey("chatgpt:team:clears_in:" + carId)){
            return redisService.getExpire("chatgpt:team:clears_in:" + carId);
        }
        if (redisService.hasKey("chatgpt:clears_in:" + carId)) {
            return redisService.getExpire("chatgpt:clears_in:" + carId);
        }
        return 0L;
    }


    @Override
    public Boolean checkCarAccount(long userId, Long relationId) {
        GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
        GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
        GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());

        if (goodsDonSku != null && goodsDonSku.getIsMirror() && goodsDonSku.getIsCar()) {
            ChatgptUser chatgptUser = getChatgptCarUser(userId, relationId, groupsRelation, goodsDonSku);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean checkCarAccountWithToken(String userToken) {

        ChatgptUser chatgptUser = getCarChatGptUserWithToken(userToken);

        return chatgptUser != null;

    }

    @Override
    public ChatgptUser getCarChatGptUser(long userId, Long relationId) {
        GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
        GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
        GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());

        if (goodsDonSku != null && goodsDonSku.getIsMirror() && goodsDonSku.getIsCar()) {
            return getChatgptCarUser(userId, relationId, groupsRelation, goodsDonSku);
        }
        return null;
    }

    @Override
    public ChatgptUser getCarChatGptUserWithToken(String userToken) {
        ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken).last(" limit 1"));
        if (chatgptUser == null) {
            //是否是用户token预备账号
            ChatgptUserTokenPrepare chatgptUserTokenPrepare = chatgptUserTokenPrepareMapper.selectOne(Wrappers.lambdaQuery(ChatgptUserTokenPrepare.class)
                    .eq(ChatgptUserTokenPrepare::getUserToken, userToken).last("limit 1"));
            if (chatgptUserTokenPrepare != null) {
                chatgptUser = generateChatGptUserUnderPrepare(chatgptUserTokenPrepare);
            }
        }
        if (chatgptUser != null) {
            if(!chatgptUser.getIsCar()){
                throw BusinessRuntimeException.getInstance("您非车队用户，请购买车队套餐");
            }
            if (chatgptUser.getRelationId() != null) {
                throw BusinessRuntimeException.getInstance("非渠道用户，请通过官网登录!");
            }
            return chatgptUser;
        }
        return null;
    }

    /**
     * 获取车队信息
     */
    @Override
    public Set<ChatgptCarInfoView> getCarInfoList(String userToken, Integer limit, Boolean isPlus) {
        SearchResult<ChatGptUserConversationRecordHistoryView> search = beanSearcher.search(ChatGptUserConversationRecordHistoryView.class, MapUtils.builder().field("userToken", userToken).limit(0, 2).build());
        Set<ChatgptCarInfoView> res = search.getDataList().stream()
                .map((historyView) -> {
                    ChatgptCarInfoView chatgptCarInfoView = buildChatgptCarInfoView(historyView.getCarId(), historyView.getCarName(), historyView.getIsPLus(), redisService.zScore(RedisService.key.CHATGPT_CAR_SCORES.getName(), historyView.getCarId()));
                    chatgptCarInfoView.setIsHistory(true);
                    chatgptCarInfoView.setScore(Math.min(redisService.zScore(RedisService.key.CHATGPT_CAR_SCORES.getName(), historyView.getCarId()), 200));

                    return chatgptCarInfoView;
                }).collect(Collectors.toCollection(LinkedHashSet::new));

        Set<ChatgptCarInfoView> lowestScoreFleets = getLowestScoreFleets(limit, isPlus);

        res.addAll(lowestScoreFleets);

        return res;
    }


    // 更新体验并计算评分
    public void updateExperienceAndScore(String carId, boolean isHighLevel, long timestamp) {
        // 定义键名
        String key = isHighLevel ? RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId : RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId;
        double scoreToAdd = isHighLevel ? 2.0 : 1.0; // 分数更新规则

        // 更新体验数据
        redisService.zAdd(key, timestamp, String.valueOf(timestamp));

        // 清理旧数据（可选）和重新计算评分（根据需要实现）
        cleanupOldExperiencesAndRecalculateScore(carId, timestamp);
    }

    // 清理旧数据和重新计算评分
    public void cleanupOldExperiencesAndRecalculateScore(String carId, long currentTimestamp) {
        long threeHoursAgo = currentTimestamp - (3 * 60 * 60 * 1000); // 3小时前的时间戳

        // 清理高级体验旧数据
        redisService.zRemoveRangeByScore(RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId, 0, threeHoursAgo);

        // 清理低级体验旧数据
        redisService.zRemoveRangeByScore(RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId, 0, threeHoursAgo);

        // 重新计算评分
        recalculateScore(carId, currentTimestamp);
    }


    // 重新计算指定车队的评分
    private void recalculateScore(String carId, long currentTimestamp) {
        // 实际应用中，你需要根据高级体验和低级体验的数量重新计算得分
        Double highExperienceScore = (double) redisService.zCount(RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId, currentTimestamp - (3 * 60 * 60 * 1000), currentTimestamp) * 2;
        Double lowExperienceScore = (double) redisService.zCount(RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId, currentTimestamp - (3 * 60 * 60 * 1000), currentTimestamp);
        double newScore = highExperienceScore + lowExperienceScore;
        if(carId.contains("T")){
            newScore = BigDecimal.valueOf(newScore).divide(BigDecimal.valueOf(5), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        redisService.zAdd(RedisService.key.CHATGPT_CAR_SCORES.getName(), newScore, carId);
    }


    // 获取得分最低的N个车队的方法
    public Set<ChatgptCarInfoView> getLowestScoreFleets(int count, Boolean isPlus) {
        Set<ZSetOperations.TypedTuple<Object>> lowestScorecarIds;
        Long fleetsSize = redisService.zCard(RedisService.key.CHATGPT_CAR_SCORES.getName());
        // 构建ChatgptCarInfoView集合
        if (fleetsSize != null && fleetsSize > 10) {
            TASK_EXECUTOR.execute(() -> {
                initFleets(true);
            });
        } else {
            initFleets(false);
        }
        lowestScorecarIds = redisService.zRangeWithScores(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0L, count - 1);
        Map<Object, Double> collect = lowestScorecarIds.stream().collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
        List<ChatgptSession> chatgptSessions = chatgptSessionMapper.selectList(Wrappers.lambdaQuery(ChatgptSession.class).in(ChatgptSession::getCarId, collect.keySet()).eq(isPlus !=null && isPlus, ChatgptSession::getIsPlus, true));
        return chatgptSessions.stream().map((chatgptSession)-> buildChatgptCarInfoView(chatgptSession.getCarId(),chatgptSession.getCarName(), chatgptSession.getIsPlus(), collect.get(chatgptSession.getCarId())))
                .sorted(Comparator.comparing(ChatgptCarInfoView::getScore)).collect(Collectors.toCollection(LinkedHashSet::new));
    }

    public void initFleets(Boolean flag) {
        LambdaQueryWrapper<ChatgptSession> wrapper = Wrappers.lambdaQuery(ChatgptSession.class);
        if (flag) {
            Set<ZSetOperations.TypedTuple<Object>> fleets = redisService.zRangeWithScores(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0L, -1);
            List<Object> collect = fleets.stream().map(ZSetOperations.TypedTuple::getValue).collect(Collectors.toList());
            wrapper.notIn(collect.size() > 0, ChatgptSession::getCarId, collect);
        }
        //如果存在未存在redis中的车辆则同步进 chatgpt:car:scores
        List<ChatgptSession> chatgptSessions = chatgptSessionMapper.selectList(wrapper.eq(ChatgptSession::getIsCar, true));

        chatgptSessions.forEach((chatgptSession) -> {
            if (!redisService.checkValueExistsInZSet(RedisService.key.CHATGPT_CAR_SCORES.getName(), chatgptSession.getCarId())) {
                redisService.zAdd(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0, chatgptSession.getCarId());
            }
        });

    }


    // 构建ChatgptCarInfoView对象
    private ChatgptCarInfoView buildChatgptCarInfoView(String carId, String carName, Integer isPlus, Double score) {
        // 在这里根据carId获取相关信息并填充到ChatgptCarInfoView对象中
        ChatgptCarInfoView view = new ChatgptCarInfoView();
        view.setCarId(carId);
        // 假设以下方法从Redis或其他服务获取数据
        view.setScore(Math.min(score, 200));
        view.setStatus(score >= 50 ? "繁忙" : "空闲"); // 或“繁忙”

        if(carName.contains("T")){
            view.setType("Team");
            Long team = carOaiLimit(carId, true);
            if (team != 0L) {
                view.setTeamExpTime(new DateTime(System.currentTimeMillis() + team * 1000));
            }
            Long aLong = carOaiLimit(carId, false);
            if (aLong != 0L) {
                view.setExpTime(new DateTime(System.currentTimeMillis() + aLong * 1000));
            }
            if (view.getExpTime() != null && view.getTeamExpTime() != null) {
                view.setStatus("全部停运");
            }else if(view.getExpTime() != null || view.getTeamExpTime() != null) {
                view.setStatus("部分停运");
            }
        }else {
            view.setType(isPlus == 1 ? "Plus" : "3.5");
            Long aLong = carOaiLimit(carId, false);
            if (aLong != 0L) {
                view.setStatus("停运");
                view.setExpTime(new DateTime(System.currentTimeMillis() + aLong * 1000));
            }
        }
        int use = getCarConversationCount(carId, 3L).intValue();
        view.setUse(use);

        view.setCarName(carName);
        return view;
    }

    @Override
    public ChatGptUserView getUserInfo(long userId, Long relationId) {
        if (checkCarAccount(userId, relationId)) {
            GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
            GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
            GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
            ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getRelationId, relationId));
            return ChatGptUserView.builder()
                    .skuName(goodsDonSku.getSubTitle())
                    .expireTime(chatgptUser.getExpireTime())
                    .limitNum(chatgptUser.getLimitNum())
                    .limitTime(chatgptUser.getLimitTime())
                    .use(Math.min(chatgptUser.getLimitNum(),getConversationCount(chatgptUser.getUserToken(), chatgptUser.getLimitTime())))
                    .build();
        } else {
            throw BusinessRuntimeException.getInstance("您还未购买该车票");
        }
    }
    @Override
    public ChatGptUserView getUserInfoWithToken(String userToken) {
        if (checkCarAccountWithToken(userToken)) {
            ChatgptUser chatgptUser = getCarChatGptUserWithToken(userToken);
            return ChatGptUserView.builder()
                    .skuName("")
                    .expireTime(chatgptUser.getExpireTime())
                    .limitNum(chatgptUser.getLimitNum())
                    .limitTime(chatgptUser.getLimitTime())
                    .use(getConversationCount(chatgptUser.getUserToken(), chatgptUser.getLimitTime()))
                    .build();
        } else {
            throw BusinessRuntimeException.getInstance("您还未购买该车票");
        }
    }

    @Override
    public void genTitleSync(String conversationId, String carid, String userToken) {
        //同步对话
        if (!StringUtils.isAnyBlank(conversationId, carid, userToken)) {
            ChatgptUserConversationRecord chatgptUserConversationRecord = chatgptUserConversationRecordMapper.selectOne(Wrappers.lambdaQuery(ChatgptUserConversationRecord.class)
                    .isNull(ChatgptUserConversationRecord::getConversationId)
                    .eq(ChatgptUserConversationRecord::getCarId, carid)
                    .eq(ChatgptUserConversationRecord::getUserToken, userToken)
                    .orderByDesc(ChatgptUserConversationRecord::getId)
                    .last(" limit 1"));
            if (chatgptUserConversationRecord != null) {
                chatgptUserConversationRecord.setConversationId(conversationId);
                chatgptUserConversationRecordMapper.updateById(chatgptUserConversationRecord);
            }
        }
    }

    @Override
    public void carLimited(String carId, String userToken, Long expTime, Boolean isTeam) {
        if (carId == null) {
            if (StringUtils.isNotBlank(userToken)) {
                ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken));
                if (chatgptUser != null && chatgptUser.getSessionId() != null) {
                    ChatgptSession chatgptSession = chatgptSessionMapper.selectById(chatgptUser.getSessionId());
                    if (chatgptSession != null) {
                        carId = chatgptSession.getCarId();
                    }
                }
            }
        }
        if(isTeam){
            redisService.set("chatgpt:team:clears_in:" + carId, expTime, expTime);
        }else {
            redisService.set("chatgpt:clears_in:" + carId, expTime, expTime);
        }


        try {
            //记录用户触发限制
            ChatgptUserCarUsedRecord chatgptUserCarUsedRecord = new ChatgptUserCarUsedRecord();
            chatgptUserCarUsedRecord.setUserToken(userToken);
            chatgptUserCarUsedRecord.setCarId(carId);

            String highCarChatKey = RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId;
            String lowCarChatKey = RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId;

            Long highCarChatNum = redisService.zCard(highCarChatKey);
            if (highCarChatNum != null) {
                chatgptUserCarUsedRecord.setGptFour(Integer.parseInt(highCarChatNum.toString()));
            }
            Long lowCarChatNum = redisService.zCard(lowCarChatKey);
            if (lowCarChatNum != null) {
                chatgptUserCarUsedRecord.setGpt(Integer.parseInt(lowCarChatNum.toString()));
            }
            chatgptUserCarUsedRecordMapper.insert(chatgptUserCarUsedRecord);
            log.info("记录userToken:{}访问对应镜像车队carId：{}操作成功", userToken, carId);
        } catch (Exception e) {
            log.info("记录userToken:{}访问对应镜像车队carId：{}操作失败e：{}", userToken, carId, StringUtil.getErrorText(e));
        }
    }

    @PostConstruct
    public void init() {
        //如果存在未存在redis中的车辆则同步进 chatgpt:car:scores
        TASK_EXECUTOR.execute(() -> {
            Set<ZSetOperations.TypedTuple<Object>> lowestScorecarIds = redisService.zRangeWithScores(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0L, -1);
            List<Object> collect = lowestScorecarIds.stream().map(ZSetOperations.TypedTuple::getValue).collect(Collectors.toList());
            List<ChatgptSession> chatgptSessions = chatgptSessionMapper.selectList(Wrappers.lambdaQuery(ChatgptSession.class).notIn(collect.size() > 0, ChatgptSession::getCarId, collect).eq(ChatgptSession::getIsPlus, 1).eq(ChatgptSession::getIsCar, true));
            chatgptSessions.forEach((chatgptSession) -> {
                if (!redisService.checkValueExistsInZSet(RedisService.key.CHATGPT_CAR_SCORES.getName(), chatgptSession.getCarId())) {
                    redisService.zAdd(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0, chatgptSession.getCarId());
                }
            });
        });
    }

}

