package com.fs.qw.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fs.common.core.domain.R;
import com.fs.common.core.redis.RedisCache;
import com.fs.common.exception.CustomException;
import com.fs.common.service.ISmsService;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.StringUtils;
import com.fs.company.domain.CompanySms;
import com.fs.company.domain.CompanySmsTemp;
import com.fs.company.service.ICompanySmsService;
import com.fs.company.service.ICompanySmsTempService;
import com.fs.fastgptApi.util.HttpUtil;
import com.fs.his.dto.SendResultDetailDTO;
import com.fs.qw.bo.SendMsgLogBo;
import com.fs.qw.domain.QwAcquisitionAssistant;
import com.fs.qw.domain.QwCompany;
import com.fs.qw.domain.QwContactAcquisitionUser;
import com.fs.qw.domain.QwContactWayUser;
import com.fs.qw.dto.acquisition.*;
import com.fs.qw.enums.SmsLogType;
import com.fs.qw.mapper.QwAcquisitionAssistantMapper;
import com.fs.qw.service.IQwAcquisitionAssistantService;
import com.fs.qw.service.IQwAcquisitionLinkInfoService;
import com.fs.qw.service.IQwCompanyService;
import com.fs.qw.service.IQwContactAcquisitionUserService;
import com.fs.qw.utils.UniqueStringUtil;
import com.fs.qw.vo.AcquisitionAssistantDetailVO;
import com.fs.qwApi.config.QwApiConfig;
import com.fs.qwApi.domain.QwResult;
import com.fs.qwApi.param.QwLinkCreateParam;
import com.fs.qwApi.service.QwApiService;
import com.fs.wx.kf.service.IWeixinKfService;
import com.fs.wx.kf.vo.WeixinKfTokenVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 企微-获客链接管理Service业务层处理
 */
@Slf4j
@Service
public class QwAcquisitionAssistantServiceImpl implements IQwAcquisitionAssistantService {

    @Autowired
    private QwAcquisitionAssistantMapper acquisitionAssistantMapper;

    @Autowired
    private IWeixinKfService weixinKfService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IQwCompanyService qwCompanyService;

    @Autowired
    private  ISmsService smsService;

    @Autowired
    private ICompanySmsTempService smsTempService;

    @Autowired
    private IQwAcquisitionLinkInfoService linkInfoService;

    @Autowired
    private ICompanySmsService companySmsService;

    @Autowired
    private IQwContactAcquisitionUserService insertQwContactWayUser;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private QwApiService qwApiService;

    // 获客链接管理-企微的ACCESS_TOKEN的key
    private static final String QW_ACQUISITION_KEY_PREFIX = "qw:acquisition:key:";

    // 获客链接-页面参数-url的key
    private static final String QW_ACQUISITION_URL_KEY_PREFIX = "qw:acquisition:url:key:";

    //获客链接短信模板code
    private static final String  SMS_LINK_TEMPLATE_CODE = "获客链接短信模板";

    //访问链接域名
    private static final String  LINK_DOMAIN = "https://c.ysyd.top/";

    /**
     * 查询企微-获客链接管理列表
     *
     * @param qwAcquisitionAssistant 企微-获客链接管理
     * @return 企微-获客链接管理
     */
    @Override
    public List<QwAcquisitionAssistant> selectQwAcquisitionAssistantList(QwAcquisitionAssistant qwAcquisitionAssistant) {
        List<QwAcquisitionAssistant> list = acquisitionAssistantMapper.selectQwAcquisitionAssistantList(qwAcquisitionAssistant);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        // 解析JSON字段
        for (QwAcquisitionAssistant assistant : list) {
            assistant.parseJsonFields();
        }
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SendResultDetailDTO sendMessageAcquisition(String phone, Long qwAcquisitionId, SendMsgLogBo sendMsgLogBo) {
        log.info("发送获客链接短信,号码：{}", phone);

        // 1. 获取短信模板
        CompanySmsTemp temp = smsTempService.selectCompanySmsTempByCode(SMS_LINK_TEMPLATE_CODE);
        if (temp == null) {
            log.info("获客链接-未找到短信模板：{}", SMS_LINK_TEMPLATE_CODE);
            throw new CustomException("获客链接-未找到短信模板");
        }

        // 2. 获取获客链接信息
        String originalContent = temp.getContent();
        QwAcquisitionAssistant acquisitionAssistant = acquisitionAssistantMapper.selectQwAcquisitionAssistantById(qwAcquisitionId);
        if (acquisitionAssistant == null) {
            log.info("获客链接-未找到获客链接id:{}", qwAcquisitionId);
            throw new CustomException("获客链接-未找到获客链接信息");
        }

        // 3. 构建短信内容
        String replaceText = LINK_DOMAIN + acquisitionAssistant.getPageParam();
        String content = originalContent.replace("${sms.friendLink}", replaceText);

        // 4. 计算需要的短信条数
        Integer needCount = calculateSmsCount(content);

        // 5. 【乐观锁扣减，支持重试】
        int maxRetries = 3;

        for (int retryCount = 0; retryCount < maxRetries; retryCount++) {
            // 先查缓存快速检查余额
            Long balance = companySmsService.getBalance(2L);
            if (balance == null || balance < needCount) {
                log.warn("短信余额不足, companyId=2, balance={}, needCount={}", balance, needCount);
                return new SendResultDetailDTO(false, "短信余额不足", null);
            }

            // 获取最新数据（含version）
            CompanySms latestSms = companySmsService.selectCompanySms(2L);
            if (latestSms == null) {
                throw new CustomException("公司短信配置不存在");
            }

            // 再次确认余额（DB为准）
            if (latestSms.getRemainSmsCount() < needCount) {
                log.warn("短信余额不足, companyId=2, remainCount={}, needCount={}",
                        latestSms.getRemainSmsCount(), needCount);
                return new SendResultDetailDTO(false, "短信余额不足", null);
            }

            Long version = latestSms.getVersion() != null ? latestSms.getVersion() : 0L;
            int updateCount = companySmsService.decrementRemainSmsCountWithVersion(2L, needCount, version);

            if (updateCount > 0) {
                log.info("乐观锁扣减成功, needCount={}, version={}", needCount, version);
                // 扣减成功，跳出循环
                break;
            }

            log.warn("乐观锁扣减失败，第{}次重试", retryCount + 1);

            // 最后一次重试失败，返回错误
            if (retryCount == maxRetries - 1) {
                return new SendResultDetailDTO(false, "系统繁忙，请稍后重试", null);
            }

            try {
                Thread.sleep(50L * (retryCount + 1));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return new SendResultDetailDTO(false, "操作被中断", null);
            }
        }

        // 6. 更新缓存
        companySmsService.updateCacheBalance(2L, -needCount);

        try {
            sendMsgLogBo.setQwAcquisitionId(acquisitionAssistant.getId());

            // 7. 发送短信
            R r = smsService.simpleSmsSend(phone, content, temp, SmsLogType.ACQUISITION_LINK, sendMsgLogBo);

            if (r != null && "200".equals(String.valueOf(r.get("code")))) {
                log.info("短信发送成功, phone={}, needCount={}", phone, needCount);
                return new SendResultDetailDTO(true, null, null);
            } else {
                // 8. 发送失败，退还余额
                String msg = r != null && r.get("msg") != null ? r.get("msg").toString() : "未知错误";
                log.warn("短信发送失败，退还余额, phone={}, needCount={}", phone, needCount);
                rollbackBalance(needCount, maxRetries);
                return new SendResultDetailDTO(false, msg, null);
            }
        } catch (Exception e) {
            log.error("发送异常，退还余额, phone=" + phone, e);
            rollbackBalance(needCount, maxRetries);
            return new SendResultDetailDTO(false, e.getMessage(), null);
        }
    }

    /**
     * 退还余额（带重试）
     */
    private void rollbackBalance(int needCount, int maxRetries) {
        for (int i = 0; i < maxRetries; i++) {
            try {
                CompanySms current = companySmsService.selectCompanySms(2L);
                if (current == null) {
                    log.error("退还短信余额失败，公司短信配置不存在");
                    return;
                }
                Long currentVersion = current.getVersion() != null ? current.getVersion() : 0L;
                int rollbackCount = companySmsService.incrementRemainSmsCountWithVersion(2L, needCount, currentVersion);
                if (rollbackCount > 0) {
                    companySmsService.updateCacheBalance(2L, needCount);
                    log.info("退还余额成功, needCount={}", needCount);
                    return;
                }
                Thread.sleep(50L);
            } catch (Exception e) {
                log.error("退还短信余额异常，第{}次重试", i + 1, e);
            }
        }
        log.error("退还短信余额失败，需要人工处理, companyId=2, needCount={}", needCount);
    }

    // ==================== 获取详情方法 ====================

    @Override
    public AcquisitionAssistantDetailVO getDetailWithQw(String linkId) {
        if (StringUtils.isEmpty(linkId)) {
            throw new CustomException("链接ID不能为空");
        }
        // 1. 查询本地记录
        QwAcquisitionAssistant query = new QwAcquisitionAssistant();
        query.setLinkId(linkId);
        List<QwAcquisitionAssistant> localRecords = acquisitionAssistantMapper.selectQwAcquisitionAssistantList(query);
        QwAcquisitionAssistant localData = localRecords.isEmpty() ? null : localRecords.get(0);

        // 2. 获取企业信息
        String corpId = localData != null ? localData.getCorpId() : null;
        QwCompany qwCompany = qwCompanyService.selectQwCompanyByCorpId(corpId);
        if (qwCompany == null) {
            throw new CustomException("未找到企业配置信息");
        }

        // 3. 调用企微API获取详情
        AcquisitionGetResponse qwDetail = null;
        try {
            AcquisitionGetRequest request = new AcquisitionGetRequest();
            request.setLinkId(linkId);

            String qwApiUrl = buildApiUrl(qwCompany.getCorpId(), qwCompany.getOpenSecret(), QwApiConfig.getAcquisition);
            qwDetail = callQwApi(qwApiUrl, request, AcquisitionGetResponse.class, "获取获客链接详情");
        } catch (Exception e) {
            log.error("调用企微API失败", e);
            // 如果API调用失败，就返回本地数据
        }
        // 4. 构建VO对象
        return buildDetailVO(localData, qwDetail, qwCompany, linkId);
    }

    // ==================== 新增方法 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public QwAcquisitionAssistant createWithQw(String corpid, String corpsecret, QwAcquisitionAssistant assistant, Long companyId) {
        // 参数校验
        if (StringUtils.isEmpty(assistant.getLinkName())) {
            throw new CustomException("链接名称不能为空");
        }
        if (assistant.getLinkName().length() > 30) {
            throw new CustomException("链接名称不能超过30个字符");
        }

        // 构建请求
        JSONObject request = new JSONObject();  // 改用JSONObject以便灵活构建
        request.put("link_name", assistant.getLinkName());
        request.put("skip_verify", Boolean.parseBoolean(assistant.getSkipVerify()));
        //request.put("mark_source", assistant.getMarkSource());

        // 构建range对象 - 即使没有值也要传空对象
        JSONObject range = new JSONObject();

        // 如果有成员列表
        if (assistant.getUserListParam() != null && !assistant.getUserListParam().isEmpty()) {
            range.put("user_list", assistant.getUserListParam());
        }

        // 如果有部门列表
        if (assistant.getDepartmentListParam() != null && !assistant.getDepartmentListParam().isEmpty()) {
            range.put("department_list", assistant.getDepartmentListParam());
        }

        // 无论是否有值，都添加range字段
        request.put("range", range);

        // 构建priority_option - 可选
        if (assistant.getPriorityType() != null && assistant.getPriorityType() > 0) {
            JSONObject priorityOption = new JSONObject();
            priorityOption.put("priority_type", assistant.getPriorityType());

            // 如果priority_type为2，需要指定priority_userid_list
            if (assistant.getPriorityType() == 2) {
                if (assistant.getPriorityUserListParam() == null || assistant.getPriorityUserListParam().isEmpty()) {
                    throw new CustomException("优先分配类型为指定范围内时，优先分配成员不能为空");
                }
                priorityOption.put("priority_userid_list", assistant.getPriorityUserListParam());
            }

            request.put("priority_option", priorityOption);
        }
        // 调用企微API
        String qwApiUrl = buildApiUrl(corpid, corpsecret, QwApiConfig.createAcquisition);

        AcquisitionCreateResponse response = callQwApi(qwApiUrl, request, AcquisitionCreateResponse.class, "创建获客链接");
        if (response.getLink() == null || StringUtils.isEmpty(response.getLink().getUrl())) {
            log.error("企微创建获客链接成功但未返回URL，response: {}", JSON.toJSONString(response));
            throw new CustomException("创建获客链接成功但未获取到访问URL");
        }
        /// 设置企微返回的数据
        String friendUrl = response.getLink().getUrl();
        assistant.setUrl(friendUrl);  // 保存企微返回的URL
        assistant.setLinkId(response.getLink().getLinkId());

        if (response.getLink().getCreateTime() != null) {
            assistant.setQwCreateTime(new Date(response.getLink().getCreateTime() * 1000));
        }
//        assistant.setQwCreateTime(new Date());
//        assistant.setUrl("6666666666");
//        assistant.setLinkId("123121");
        //如果这个随机参数已存在，则重新生成
        String randomParam =generateUniquePageParam();

        assistant.setPageParam(randomParam);

        // 生成scheme
        assistant.setScheme(generateScheme(friendUrl));

        // 设置本地字段并保存
        setLocalFields(assistant, true);
        acquisitionAssistantMapper.insertQwAcquisitionAssistant(assistant);

        String userLimitJson = assistant.getUserLimitJson();
        List<QwContactAcquisitionUser> acquisitionUserList = JSON.parseArray(userLimitJson, QwContactAcquisitionUser.class);
        for (QwContactAcquisitionUser acquisitionUser : acquisitionUserList) {
            acquisitionUser.setDayCount(acquisitionUser.getLimitCount());
            acquisitionUser.setLinkId(assistant.getLinkId());
            acquisitionUser.setCompanyId(companyId);
            acquisitionUser.setCorpId(corpid);
            insertQwContactWayUser.insertQwContactAcquisitionUser(acquisitionUser);
        }


        // ========== 缓存URL，便于后续通过pageParam访问 ==========
        try {
            String cacheKey = QW_ACQUISITION_URL_KEY_PREFIX + randomParam;
            Integer cacheExpire = 2; // 默认缓存2天
            redisCache.setCacheObject(cacheKey, friendUrl, cacheExpire, TimeUnit.DAYS);
            log.info("获客链接URL缓存成功, pageParam: {}, url: {}", randomParam, friendUrl);
        } catch (Exception e) {
            // 缓存失败不影响主流程，但需要记录日志
            log.error("获客链接URL缓存失败, pageParam: {}", randomParam, e);
        }
        return assistant;
    }

    // ==================== 编辑方法 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public QwAcquisitionAssistant updateWithQw(String corpid, String corpsecret, QwAcquisitionAssistant assistant,Long companyId) {
        // 参数校验
        if (assistant.getId() == null) {
            throw new CustomException("ID不能为空");
        }
        if (StringUtils.isEmpty(assistant.getLinkId())) {
            throw new CustomException("链接ID不能为空");
        }

        // 查询本地是否存在
        QwAcquisitionAssistant existAssistant = acquisitionAssistantMapper.selectQwAcquisitionAssistantById(assistant.getId());
        if (existAssistant == null) {
            throw new CustomException("获客链接不存在");
        }

        // 构建请求
        AcquisitionBaseRequest request = new AcquisitionBaseRequest();
        request.setLinkId(assistant.getLinkId());
        if (StringUtils.isNotEmpty(assistant.getLinkName())) {
            request.setLinkName(assistant.getLinkName());
        }
        request.setSkipVerify(Boolean.parseBoolean(assistant.getSkipVerify()));

        AcquisitionRange range=new AcquisitionRange();
        range.setUserList(assistant.getUserListParam());
        request.setRange(range);
        //request.setMarkSource(assistant.getMarkSource());

//         调用企微API
        String qwApiUrl = buildApiUrl(corpid, corpsecret, QwApiConfig.updateAcquisition);
        AcquisitionUpdateResponse response = callQwApi(qwApiUrl, request, AcquisitionUpdateResponse.class, "更新获客链接");

        // 更新本地字段
        setLocalFields(assistant, false);
        //重新生成页面参数，需要修改对应redis缓存
        String oldPageParam = existAssistant.getPageParam();
        String oldKey = QW_ACQUISITION_URL_KEY_PREFIX + oldPageParam;
        redisCache.deleteObject(oldKey);
        String newPageParam =generateUniquePageParam();
        String newKey = QW_ACQUISITION_URL_KEY_PREFIX + newPageParam;
        Integer cacheExpire = 2;//默认缓存2天
        redisCache.setCacheObject(newKey, existAssistant.getUrl(), cacheExpire, TimeUnit.DAYS);

        assistant.setPageParam(newPageParam);

        int rows = acquisitionAssistantMapper.updateQwAcquisitionAssistant(assistant);
        if (rows <= 0) {
            throw new CustomException("本地数据更新失败");
        }

        //先根据linkId查询出所有ID，再删除
        List<QwContactAcquisitionUser> userList = insertQwContactWayUser.list(
                new LambdaQueryWrapper<QwContactAcquisitionUser>()
                        .eq(QwContactAcquisitionUser::getLinkId, existAssistant.getLinkId()));

        if (!CollectionUtils.isEmpty(userList)) {
            List<Long> ids = userList.stream()
                    .map(QwContactAcquisitionUser::getId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

            if (!ids.isEmpty()) {
                insertQwContactWayUser.removeByIds(ids);
            }
        }

        String userLimitJson = assistant.getUserLimitJson();
        List<QwContactAcquisitionUser> acquisitionUserList = JSON.parseArray(userLimitJson, QwContactAcquisitionUser.class);
        for (QwContactAcquisitionUser acquisitionUser : acquisitionUserList) {
            acquisitionUser.setDayCount(acquisitionUser.getLimitCount());
            acquisitionUser.setLinkId(existAssistant.getLinkId());
            acquisitionUser.setCompanyId(companyId);
            acquisitionUser.setCorpId(corpid);
            insertQwContactWayUser.insertQwContactAcquisitionUser(acquisitionUser);
        }


        return assistant;
    }

    // ==================== 删除方法 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteWithQw(String corpid, String corpsecret, QwAcquisitionAssistant assistant) {
        // 参数校验
        if (assistant == null || assistant.getId() == null) {
            throw new CustomException("参数不能为空");
        }
        if (StringUtils.isEmpty(assistant.getLinkId())) {
            throw new CustomException("链接ID不能为空");
        }

        // 查询本地是否存在（获取完整的记录，包括pageParam）
        QwAcquisitionAssistant existAssistant = acquisitionAssistantMapper.selectQwAcquisitionAssistantById(assistant.getId());
        if (existAssistant == null) {
            throw new CustomException("获客链接不存在");
        }

        // 构建删除请求
        JSONObject request = new JSONObject();
        request.put("link_id", assistant.getLinkId());

        // 调用企微API
        String qwApiUrl = buildApiUrl(corpid, corpsecret, QwApiConfig.deleteAcquisition);
        AcquisitionDeleteResponse response = callQwApi(qwApiUrl, request, AcquisitionDeleteResponse.class, "删除获客链接");

        // ========== 删除Redis缓存 ==========
        try {
            // 1. 删除pageParam对应的URL缓存
            if (StringUtils.isNotEmpty(existAssistant.getPageParam())) {
                String urlCacheKey = QW_ACQUISITION_URL_KEY_PREFIX + existAssistant.getPageParam();
                redisCache.deleteObject(urlCacheKey);
                log.info("删除获客链接URL缓存成功, pageParam: {}, key: {}",
                        existAssistant.getPageParam(), urlCacheKey);
            }
        } catch (Exception e) {
            // 缓存删除失败不应该影响主流程，但需要记录日志
            log.error("删除获客链接缓存失败, id: {}, linkId: {}, pageParam: {}",
                    existAssistant.getId(), existAssistant.getLinkId(),
                    existAssistant.getPageParam(), e);
        }

        // 删除本地记录
        int rows = acquisitionAssistantMapper.deleteQwAcquisitionAssistantById(assistant.getId());

        //删除新增链接记录
        Long[] qwAcquisitionAssistantIds = {assistant.getId()};
        linkInfoService.deleteQwAcquisitionLinkInfoByQwAcquisitionAssistantIds(qwAcquisitionAssistantIds);

        if (rows <= 0) {
            throw new CustomException("本地数据删除失败");
        }

        log.info("获客链接删除成功, id: {}, linkId: {}, pageParam: {}",
                existAssistant.getId(), existAssistant.getLinkId(),
                existAssistant.getPageParam());
    }

    // ==================== 查询方法 ====================

    @Override
    public QwAcquisitionAssistant selectQwAcquisitionAssistantById(Long id) {
        QwAcquisitionAssistant assistant = acquisitionAssistantMapper.selectQwAcquisitionAssistantById(id);
        if (assistant != null) {
            assistant.parseJsonFields();
        }
        return assistant;
    }

    @Override
    public String selectQwAcquisitionUrlByPageParam(String pageParam) {
        String key = QW_ACQUISITION_URL_KEY_PREFIX + pageParam;
        String friendUrl = null;

        try {
            Object cacheObj = redisCache.getCacheObject(key);
            if (cacheObj instanceof String) {
                friendUrl = (String) cacheObj;
                // 处理缓存空值的情况
                if ("NULL".equals(friendUrl)) {
                    return null;
                }
                log.debug("从缓存获取获客链接url成功,pageParam:{}", pageParam);
                return friendUrl;
            }
        } catch (Exception e) {
            log.warn("从缓存获取获客链接url异常, 将重新获取, pageParam:{}", pageParam);
        }

        // 缓存中没有，查询数据库
        friendUrl = acquisitionAssistantMapper.selectQwAcquisitionUrlByPageParam(pageParam);

        // 缓存处理（包括空值缓存）
        if (friendUrl == null) {
            int nullCacheExpire = 10; // 10秒
            redisCache.setCacheObject(key, "NULL", nullCacheExpire, TimeUnit.SECONDS);
            log.info("获客链接URL不存在，缓存空值10秒, pageParam:{}", pageParam);
            return null;
        } else {
            // 正常值仍缓存2天
            Integer cacheExpire = 2;
            redisCache.setCacheObject(key, friendUrl, cacheExpire, TimeUnit.DAYS);
            log.info("获客链接URL缓存成功, pageParam:{}", pageParam);
        }

        return friendUrl;
    }


    /**
     * 获取access_token并返回完整URL
     */
    private String buildApiUrl(String corpid, String corpsecret, String apiPath) {
        WeixinKfTokenVO token = getAccessToken(corpid, corpsecret);

        if (token == null || StringUtils.isEmpty(token.getAccess_token())) {
            log.error("获取access_token失败, corpid:{}", corpid);
            throw new CustomException("获客链接管理-获取企业微信access_token失败");
        }

        return apiPath + "?access_token=" + token.getAccess_token();
    }

    /**
     * 获取access_token（使用实际有效期）
     */
    private WeixinKfTokenVO getAccessToken(String corpid, String corpsecret) {
        String key = QW_ACQUISITION_KEY_PREFIX + corpid;

        // 1. 先从缓存获取
        WeixinKfTokenVO token = null;
        try {
            Object cacheObj = redisCache.getCacheObject(key);
            if (cacheObj instanceof WeixinKfTokenVO) {
                token = (WeixinKfTokenVO) cacheObj;
                log.debug("从缓存获取token成功, corpid:{}", corpid);
            }
        } catch (Exception e) {
            log.warn("从缓存获取token异常, 将重新获取, corpid:{}", corpid);
        }

        // 2. 缓存中没有，则重新获取
        if (token == null) {
            log.info("缓存中没有token，重新获取, corpid:{}", corpid);
            try {
                // 获取新token
                token = weixinKfService.getToken(corpid, corpsecret);

                // 存入缓存，使用企业微信返回的实际有效期
                if (token != null && StringUtils.isNotEmpty(token.getAccess_token())) {
                    Integer expiresIn = token.getExpires_in();
                    if (expiresIn == null) {
                        // 如果返回中没有expires_in，默认2小时
                        expiresIn = 7200;
                        log.warn("token返回中没有expires_in字段，使用默认值7200秒");
                    }

                    // 实际缓存时间比有效期稍短（提前5分钟过期），避免边界问题
                    Integer cacheExpire = expiresIn - 300; // 提前5分钟
                    if (cacheExpire <= 0) {
                        cacheExpire = expiresIn;
                    }

                    redisCache.setCacheObject(key, token, cacheExpire, TimeUnit.SECONDS);
                    log.info("token缓存成功, corpid:{}, 有效期:{}秒, 缓存时间:{}秒",
                            corpid, expiresIn, cacheExpire);
                }
            } catch (Exception e) {
                log.error("获取token失败, corpid:{}, error:{}", corpid, e.getMessage());
                return null;
            }
        }

        return token;
    }

    /**
     * 调用企微API并统一处理返回结果
     */
    private <T> T callQwApi(String qwApiUrl, Object request, Class<T> responseClass, String operationName) {
        log.info("调用企微{}，参数：{}", operationName, JSON.toJSONString(request));
        String result = HttpUtil.sendAuthPost(request, qwApiUrl);
        log.info("企微{}响应：{}", operationName, result);

        if (StringUtils.isEmpty(result)) {
            throw new CustomException("调用企微API失败，返回为空");
        }

        T response = JSON.parseObject(result, responseClass);

        // 通过反射获取errcode（所有响应都有这个字段）
        try {
            java.lang.reflect.Field errcodeField = responseClass.getDeclaredField("errcode");
            errcodeField.setAccessible(true);
            Integer errcode = (Integer) errcodeField.get(response);

            if (errcode != null && errcode != 0) {
                java.lang.reflect.Field errmsgField = responseClass.getDeclaredField("errmsg");
                errmsgField.setAccessible(true);
                String errmsg = (String) errmsgField.get(response);
                throw new CustomException("企微" + operationName + "失败：" + errmsg);
            }
        } catch (Exception e) {
            if (e instanceof CustomException) {
                throw (CustomException) e;
            }
            log.error("解析企微响应失败", e);
        }

        return response;
    }

    /**
     * 生成范围描述
     */
    private String generateRangeDesc(QwAcquisitionAssistant assistant) {
        StringBuilder desc = new StringBuilder();
        if (assistant.getUserListParam() != null && !assistant.getUserListParam().isEmpty()) {
            desc.append(assistant.getUserListParam().size()).append("名成员");
        }
        if (assistant.getDepartmentListParam() != null && !assistant.getDepartmentListParam().isEmpty()) {
            if (desc.length() > 0) desc.append(" + ");
            desc.append(assistant.getDepartmentListParam().size()).append("个部门");
        }
        return desc.length() > 0 ? desc.toString() : "未设置范围";
    }

    /**
     * 生成scheme
     */
    private String generateScheme(String qwApiUrl) {
        if (StringUtils.isNotEmpty(qwApiUrl)) {
            try {
                String encodedUrl = java.net.URLEncoder.encode(qwApiUrl, "UTF-8");
                return "weixin://biz/ww/profile/" + encodedUrl;
            } catch (Exception e) {
                log.warn("生成scheme失败", e);
            }
        }
        return null;
    }

    /**
     * 设置本地通用字段
     */
    private void setLocalFields(QwAcquisitionAssistant assistant, boolean isCreate) {
        if (isCreate) {
            assistant.setStatus(1);
            assistant.setDelFlag("0");
            assistant.setCreateTime(new Date());
        } else {
            assistant.setUpdateTime(new Date());
        }
        assistant.setSyncTime(DateUtils.getNowDate());
        assistant.buildJsonFields();
        assistant.setRangeDesc(generateRangeDesc(assistant));

        if (StringUtils.isEmpty(assistant.getScheme())) {
            assistant.setScheme(generateScheme(assistant.getUrl()));
        }
    }

    /**
     * 构建统一的VO对象
     */
    private AcquisitionAssistantDetailVO buildDetailVO(QwAcquisitionAssistant localData,
                                                       AcquisitionGetResponse qwDetail,
                                                       QwCompany qwCompany,
                                                       String linkId) {
        AcquisitionAssistantDetailVO vo = new AcquisitionAssistantDetailVO();

        // 处理企微API返回的数据
        if (qwDetail != null) {
            // 基础信息
            if (qwDetail.getLink() != null) {
                AcquisitionGetResponse.LinkDetail link = qwDetail.getLink();
                vo.setLinkId(linkId);
                vo.setLinkName(link.getLinkName());
                vo.setUrl(link.getUrl());
                vo.setSkipVerify(link.getSkipVerify());
                vo.setQwCreateTime(link.getCreateTime());
            }

            // 范围信息处理
            if (qwDetail.getRange() != null) {
                AcquisitionGetResponse.RangeInfo range = qwDetail.getRange();

                // 将userList和departmentList组合成JSON字符串
                Map<String, Object> rangeUserListMap = new HashMap<>();
                Map<String, Object> rangeDepartmentListMap = new HashMap<>();
                rangeUserListMap.put("userList", range.getUserList() != null ? range.getUserList() : new ArrayList<>());
                rangeDepartmentListMap.put("departmentList", range.getDepartmentList() != null ? range.getDepartmentList() : new ArrayList<>());
                vo.setUserList(JSON.toJSONString(rangeUserListMap));
                vo.setDepartmentList(JSON.toJSONString(rangeDepartmentListMap));

                // 生成范围描述
                vo.setRangeDesc(buildRangeDesc(range));
            }

            // 优先分配信息处理
            if (qwDetail.getPriorityOption() != null) {
                AcquisitionGetResponse.PriorityInfo priority = qwDetail.getPriorityOption();
                vo.setPriorityType(priority.getPriorityType() != null ? priority.getPriorityType() : 0);

                // 将优先分配成员列表转换为JSON字符串
                if (priority.getPriorityUseridList() != null) {
                    vo.setPriorityUserList(JSON.toJSONString(priority.getPriorityUseridList()));
                } else {
                    vo.setPriorityUserList("[]");
                }
            }
        }

        // 补充本地数据
        if (localData != null) {
            // 如果企微数据中没有的字段，使用本地数据
            if (vo.getLinkId() == null) vo.setLinkId(localData.getLinkId());
            if (vo.getLinkName() == null) vo.setLinkName(localData.getLinkName());
            if (vo.getUrl() == null) vo.setUrl(localData.getUrl());
            if (vo.getSkipVerify() == null) vo.setSkipVerify(localData.getSkipVerify());
            if (vo.getUserList() == null) vo.setUserList(localData.getUserList());
            if (vo.getPriorityType() == null) vo.setPriorityType(localData.getPriorityType());
            if (vo.getPriorityUserList() == null) vo.setPriorityUserList(localData.getPriorityUserList());
            if (vo.getQwUserTableIdList() == null) vo.setQwUserTableIdList(localData.getQwUserTableIdList());
            if (vo.getRangeDesc() == null) vo.setRangeDesc(localData.getRangeDesc());

            // 本地记录特有的字段
            vo.setId(localData.getId());
            vo.setStatus(localData.getStatus());
            vo.setSyncTime(localData.getSyncTime());
            vo.setRemark(localData.getRemark());
            vo.setCorpId(localData.getCorpId());
            vo.setScheme(localData.getScheme());
            vo.setUserLimitJson(localData.getUserLimitJson());
            vo.setSpareUserIds(localData.getSpareUserIds());
        } else {
            // 纯企微数据，设置默认值
            vo.setStatus(1);
            vo.setCorpId(qwCompany.getCorpId());
            if (vo.getPriorityType() == null) vo.setPriorityType(0);
            if (vo.getPriorityUserList() == null) vo.setPriorityUserList("[]");
            if (vo.getUserList() == null) vo.setUserList("{\"userList\":[]}");
            if (vo.getDepartmentList() == null) vo.setDepartmentList("{\"departmentList\":[]}");
            if (vo.getRangeDesc() == null) vo.setRangeDesc("全企业");
        }

        return vo;
    }

    /**
     * 生成范围描述 - 确保方法签名正确
     */
    private String buildRangeDesc(AcquisitionGetResponse.RangeInfo range) {
        if (range == null) {
            return "全企业";
        }

        List<String> userList = range.getUserList();
        List<Integer> departmentList = range.getDepartmentList();

        StringBuilder desc = new StringBuilder();

        if (userList != null && !userList.isEmpty()) {
            desc.append("成员(").append(userList.size()).append("人)");
        }

        if (departmentList != null && !departmentList.isEmpty()) {
            if (desc.length() > 0) {
                desc.append("、");
            }
            desc.append("部门(").append(departmentList.size()).append("个)");
        }

        return desc.length() > 0 ? desc.toString() : "全企业";
    }

    /**
     * 生成唯一的页面参数（针对2000条数据的优化版本）
     */
    private String generateUniquePageParam() {
        // 获取所有已存在的pageParam（只取需要的字段）
        List<String> existingParams = acquisitionAssistantMapper.selectAllPageParams();
        //使用Set，提高查找效率 O(1)
        Set<String> paramSet = new HashSet<>(existingParams);

        int maxAttempts = 10; // 设置最大尝试次数
        int attempt = 0;

        while (attempt < maxAttempts) {
            // 生成6位随机码
            String candidate = UniqueStringUtil.generateTimeBasedUnique(6);

            // 使用Set的contains方法，O(1)复杂度
            if (!paramSet.contains(candidate)) {
                log.debug("生成页面参数成功: {}, 尝试次数: {}", candidate, attempt + 1);
                return candidate;
            }

            attempt++;
            log.debug("页面参数 {} 已存在，重新生成，第{}次尝试", candidate, attempt);
        }

        // 如果多次尝试都失败，使用+1随机数方案
        String finalParam = UniqueStringUtil.generateTimeBasedUnique(7);
        log.warn("多次尝试后使用7位参数: {}", finalParam);
        return finalParam;
    }
    //根据短信文字内容计算短信条数
    private int calculateSmsCount(String content) {
        if (content == null) return 1;
        int counts = content.length() / 67;
        if (content.length() % 67 > 0) {
            counts = counts + 1;
        }
        if (counts == 0) {
            counts = 1;
        }
        return counts;
    }

    @Override
    public void resetAcquisitionLinkUserLimit() {
        long startTimeMillis = System.currentTimeMillis();
        log.info("====== 开始重置获客链接用户每日添加额度 ======");

        try {
            QwAcquisitionAssistant queryParam = new QwAcquisitionAssistant();
            queryParam.setDelFlag("0");
            List<QwAcquisitionAssistant> assistants = acquisitionAssistantMapper.selectQwAcquisitionAssistantList(queryParam);

            if (assistants == null || assistants.isEmpty()) {
                log.info("没有需要处理的获客链接");
                return;
            }

            int processedCount = 0;
            int restoredUserCount = 0;

            for (QwAcquisitionAssistant assistant : assistants) {
                try {
                    if (assistant.getUserLimitJson() != null && !assistant.getUserLimitJson().isEmpty()) {
                        com.alibaba.fastjson.JSONArray userLimitArray = com.alibaba.fastjson.JSON.parseArray(assistant.getUserLimitJson());

                        List<String> restoredUserList = new java.util.ArrayList<>();
                        List<Long> restoredQwUserTableIdList = new java.util.ArrayList<>();

                        for (int i = 0; i < userLimitArray.size(); i++) {
                            com.alibaba.fastjson.JSONObject userLimit = userLimitArray.getJSONObject(i);
                            String userId = userLimit.getString("userId");
                            Long qwUserId = userLimit.getLong("qwUserId");

                            restoredUserList.add(userId);
                            if (qwUserId != null) {
                                restoredQwUserTableIdList.add(qwUserId);
                            }
                        }

                        assistant.setUserList(com.alibaba.fastjson.JSON.toJSONString(restoredUserList));
                        assistant.setQwUserTableIdList(com.alibaba.fastjson.JSON.toJSONString(restoredQwUserTableIdList));


                        // 构建请求
                        QwLinkCreateParam linkCreateParam=new QwLinkCreateParam();
                        linkCreateParam.setLink_id(assistant.getLinkId());

                        QwLinkCreateParam.Range range=new QwLinkCreateParam.Range();
                        range.setUser_list(JSON.parseArray(assistant.getUserList(), String.class));
                        linkCreateParam.setRange(range);

                        //调用企微API
                        QwResult qwResult = qwApiService.linkUpdate(linkCreateParam, assistant.getCorpId());
                        if (qwResult.getErrcode() == 0) {
                            acquisitionAssistantMapper.updateQwAcquisitionAssistant(assistant);
                            restoredUserCount += restoredUserList.size();
                            processedCount++;

                        }else {
                            log.error("修改渠道活码 失败！"+linkCreateParam+":"+qwResult.getErrmsg());
                        }



                        restoredUserCount += restoredUserList.size();
                        processedCount++;

                        log.info("获客链接{}已恢复{}个用户的添加额度", assistant.getLinkId(), restoredUserList.size());
                    }
                } catch (Exception e) {
                    log.error("处理获客链接{}时出错", assistant.getId(), e);
                }
            }

            long endTimeMillis = System.currentTimeMillis();
            log.info("====== 获客链接用户额度重置完成，处理{}个链接，恢复{}个用户，耗时 {} 毫秒 ======",
                    processedCount, restoredUserCount, (endTimeMillis - startTimeMillis));
        } catch (Exception e) {
            log.error("重置获客链接用户额度任务执行失败", e);
        }
    }

}
