package com.fs.his.service.impl;

import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.stream.Collectors;

import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fs.common.constant.HttpStatus;
import com.fs.common.core.domain.R;
import com.fs.common.core.domain.ResponseResult;
import com.fs.common.core.domain.entity.SysDictData;
import com.fs.common.core.page.TableDataInfo;
import com.fs.common.core.redis.RedisCache;
import com.fs.common.enums.ImTypeEnum;
import com.fs.common.param.LoginMaWxParam;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.DictUtils;
import com.fs.common.utils.ParseUtils;
import com.fs.common.utils.StringUtils;
import com.fs.company.cache.ICompanyTagCacheService;
import com.fs.company.cache.ICompanyUserCacheService;
import com.fs.company.domain.*;
import com.fs.company.mapper.*;
import com.fs.company.service.ICompanyTagService;
import com.fs.course.domain.FsUserCompanyUser;
import com.fs.course.mapper.FsUserCourseVideoMapper;
import com.fs.course.param.CourseAnalysisParam;
import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
import com.fs.course.param.newfs.UserCourseVideoPageParam;
import com.fs.course.service.IFsUserCompanyUserService;
import com.fs.course.vo.newfs.FsCourseAnalysisCountVO;
import com.fs.course.vo.newfs.FsCourseAnalysisVO;
import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
import com.fs.his.config.IntegralConfig;
import com.fs.his.domain.*;
import com.fs.his.domain.FsUserAddress;
import com.fs.his.domain.FsUserIntegralLogs;
import com.fs.his.dto.FindUsersByDTO;
import com.fs.his.enums.FsUserIntegralLogTypeEnum;
import com.fs.his.mapper.*;
import com.fs.his.param.FindUserByParam;
import com.fs.his.param.FsUserAddIntegralTemplateParam;
import com.fs.his.param.FsUserParam;
import com.fs.his.service.IFsUserIntegralLogsService;
import com.fs.his.service.IFsUserProjectTagService;
import com.fs.his.service.IFsUserWxService;
import com.fs.his.vo.FsUserVO;
import com.fs.his.vo.FsUserExportListVO;
import com.fs.his.vo.FsUserFollowDoctorVO;
import com.fs.his.vo.UserVo;
import com.fs.im.config.ImTypeConfig;
import com.fs.im.service.OpenIMService;
import com.fs.hisStore.domain.FsStoreOrderScrm;
import com.fs.hisStore.domain.FsUserBillScrm;
import com.fs.hisStore.domain.FsUserScrm;
import com.fs.hisStore.enums.BillDetailEnum;
import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
import com.fs.hisStore.service.IFsUserBillScrmService;
import com.fs.hisStore.vo.FsCompanyUserListQueryVO;
import com.fs.live.vo.HisFsUserVO;
import com.fs.qw.cache.IQwExternalContactCacheService;
import com.fs.qw.dto.FsUserTransferParamDTO;
import com.fs.qw.param.QwFsUserParam;
import com.fs.qw.vo.QwFsUserVO;
import com.fs.store.domain.FsUserCourseCount;
import com.fs.store.mapper.FsUserCourseCountMapper;
import com.fs.store.param.h5.FsUserPageListParam;
import com.fs.store.param.h5.UserStatisticsCommonParam;
import com.fs.store.service.cache.IFsUserCourseCountCacheService;
import com.fs.store.vo.FsUserLastCount;
import com.fs.store.vo.h5.*;
import com.fs.system.mapper.SysDictDataMapper;
import com.fs.system.service.ISysConfigService;
import com.fs.watch.domain.WatchUser;
import com.fs.watch.domain.vo.FsUserAndCompanyAndDoctorVo;
import com.fs.watch.service.WatchUserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.Asserts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fs.his.service.IFsUserService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import static com.fs.his.utils.PhoneUtil.*;
import static com.fs.hisStore.enums.BillDetailEnum.CATEGORY_1;
import static com.fs.hisStore.enums.BillDetailEnum.CATEGORY_3;

/**
 * 用户Service业务层处理
 *
 * @author fs
 * @date 2023-06-07
 */
@Service
public class FsUserServiceImpl implements IFsUserService {
    Logger logger = LoggerFactory.getLogger(getClass());
    ;
    @Autowired
    private FsUserMapper fsUserMapper;
    @Autowired
    private CompanyUserMapper companyUserMapper;
    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private FsUserAddressMapper fsUserAddressMapper;
    @Autowired
    private FsUserCourseVideoMapper userCourseVideoMapper;
    @Autowired
    private FsStoreOrderMapper fsStoreOrderMapper;
    @Autowired
    private FsFollowMapper fsFollowMapper;
    @Autowired
    private WatchUserService watchUserService;

    @Autowired
    private ICompanyTagService companyTagService;

    @Autowired
    CompanyTagMapper companyTagMapper;

    @Autowired
    private CompanyTagUserMapper companyTagUserMapper;
    @Autowired
    private FsPackageMapper packageMapper;
    @Autowired
    private FsPackageSolarTermMapper packageSolarTermMapper;

    @Autowired
    private ICompanyUserCacheService companyUserCacheService;

    @Autowired
    private IFsUserCourseCountCacheService fsUserCourseCountCacheService;

    @Autowired
    private ICompanyTagCacheService companyTagCacheService;
    @Autowired
    private IFsUserIntegralLogsService userIntegralLogsService;
    @Autowired
    private SysDictDataMapper dictDataMapper;
    @Autowired
    private IFsUserCompanyUserService userCompanyUserService;
    @Autowired
    private IQwExternalContactCacheService qwExternalContactCacheService;

    @Autowired
    private CompanyRoleMapper companyRoleMapper;

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IFsUserProjectTagService userProjectTagService;

    @Autowired
    private FsUserCourseCountMapper fsUserCourseCountMapper;

    @Autowired
    private OpenIMService openIMService;
    @Autowired
    private IFsUserBillScrmService billService;
    @Autowired
    private FsStoreOrderScrmMapper storeOrderMapper;

    @Autowired
    private IFsUserWxService fsUserWxService;


    /**
     * 查询用户
     *
     * @param userId 用户主键
     * @return 用户
     */
    @Override
    public FsUser selectFsUserByUserId(Long userId) {
        return fsUserMapper.selectFsUserByUserId(userId);
    }

    @Override
    public List<FindUsersByDTO> findUserByParam(FindUserByParam param) {
        return fsUserMapper.findUsersByParam(param);
    }

    /**
     * 查询用户列表
     *
     * @param fsUser 用户
     * @return 用户
     */
    @Override
    public List<FsUser> selectFsUserList(FsUser fsUser) {
        return fsUserMapper.selectFsUserList(fsUser);
    }

    /**
     * 新增用户
     *
     * @param fsUser 用户
     * @return 结果
     */
    @Override
    @Transactional
    public int insertFsUser(FsUser fsUser) {
        fsUser.setCreateTime(DateUtils.getNowDate());
        if (StringUtils.isNotEmpty(fsUser.getPhone())) {
            fsUser.setPhone(encryptPhone(fsUser.getPhone()));
        }
        int i = fsUserMapper.insertFsUser(fsUser);

        //生成腕表模块默认设置
        WatchUser watchUser = new WatchUser();
        watchUser.setUserId(fsUser.getUserId());
        watchUserService.insert(watchUser);
        return i;
    }

    /**
     * 修改用户
     *
     * @param fsUser 用户
     * @return 结果
     */
    @Override
    public int updateFsUser(FsUser fsUser) {
        fsUser.setUpdateTime(DateUtils.getNowDate());
        if (fsUser.getPhone() != null && fsUser.getPhone().length() == 11 && fsUser.getPhone().matches("\\d+")) {
            fsUser.setPhone(encryptPhone(fsUser.getPhone()));
        } else {
            fsUser.setPhone(null);
        }
        if (ObjectUtils.isNotEmpty(fsUser.getLevel())&&fsUser.getLevel().equals(1)){
            fsUser.setIsShow(1);
        }else {
            fsUser.setIsShow(0);
        }
        return fsUserMapper.updateFsUser(fsUser);
    }

    /**
     * 批量删除用户
     *
     * @param userIds 需要删除的用户主键
     * @return 结果
     */
    @Override
    public int deleteFsUserByUserIds(Long[] userIds) {
        for (Long userId : userIds) {
            fsUserMapper.updateFsUserByUserId(userId);
        }
        return userIds.length;
    }

    /**
     * 删除用户信息
     *
     * @param userId 用户主键
     * @return 结果
     */
    @Override
    public int deleteFsUserByUserId(Long userId) {
        return fsUserMapper.updateFsUserByUserId(userId);
    }

    /**
     * 列表查询
     * @param fsUser
     * @return
     */
    @Override
    public List<FsUserVO> selectFsUserListVO(FsUserParam fsUser) {
        return fsUserMapper.selectFsUserListVO(fsUser);
    }

    /**
     * 导出用户列表
     * @param fsUser
     * @return
     */
    @Override
    public List<FsUserExportListVO> selectFsUserExportListVO(FsUserParam fsUser) {
        return fsUserMapper.selectFsUserExportListVO(fsUser);
    }

    @Override
    public FsUser selectFsUserByOpenId(String openId) {
        return fsUserMapper.selectFsUserByOpenId(openId);
    }

    @Override
    public FsUser selectFsUserByCourseOpenId(String openId) {
        return fsUserMapper.selectFsUserByCourseOpenId(openId);
    }

    @Override
    public FsUser selectFsUserByCourseMaOpenId(String openId) {
        return fsUserMapper.selectFsUserByCourseMaOpenId(openId);
    }

    @Override
    public FsUser selectFsUserByPhone(String phone) {
        return fsUserMapper.selectFsUserByPhone(phone);
    }

    @Override
    public List<FsUserAddress> selectFsUserAddressByUserId(Long userId) {
        FsUserAddress fsUserAddress = new FsUserAddress();
        fsUserAddress.setUserId(userId);
        return fsUserAddressMapper.selectFsUserAddressList(fsUserAddress);
    }

    @Override
    public List<UserVo> selectUserVOList(String name) {
        return fsUserAddressMapper.selectUserVOList(name);
    }

    @Override
    public List<FsUserVO> selectFsUserListVOByComponentsUser(FsUserParam fsUser) {
        return fsUserMapper.selectFsUserListVOByComponentsUser(fsUser);
    }

    @Autowired
    private FsUserIntegralLogsMapper integralLogsMapper;

    @Autowired
    private ISysConfigService configService;

    @Override
    @Transactional
    public void addUserIntegral(BigDecimal payMoney, Long userId, Long orderId, Integer orderType) {
        String json = configService.selectConfigByKey("his.integral");
        IntegralConfig config = JSONUtil.toBean(json, IntegralConfig.class);

        int points = payMoney.intValue() * config.getIntegralRatio();

        // 节气套餐包双倍积分
        if (isSolarTerm(orderId, orderType)) {
            points *= 2;
        }

        FsUserAddIntegralTemplateParam integralTemplateParam = new FsUserAddIntegralTemplateParam();
        integralTemplateParam.setUserId(userId);
        integralTemplateParam.setLogType(FsUserIntegralLogTypeEnum.TYPE_2.getValue());
        integralTemplateParam.setBusinessId(orderId.toString());
        integralTemplateParam.setPoints(points);
        userIntegralLogsService.addIntegralTemplate(integralTemplateParam);
    }

    /**
     * 判断是否节气套餐包
     */
    private boolean isSolarTerm(Long orderId, Integer orderType) {
        if (orderType == 2) {
            FsStoreOrder fsStoreOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderId(orderId);
            if (Objects.nonNull(fsStoreOrder.getPackageId())) {
                FsPackage fsPackage = packageMapper.selectFsPackageByPackageId(fsStoreOrder.getPackageId());
                if (Objects.nonNull(fsPackage) && Objects.nonNull(fsPackage.getSolarTerm())) {
                    Wrapper<FsPackageSolarTerm> queryWrapper = Wrappers.<FsPackageSolarTerm>lambdaQuery()
                            .eq(FsPackageSolarTerm::getId, fsPackage.getSolarTerm())
                            .eq(FsPackageSolarTerm::getIsDel, 0);
                    FsPackageSolarTerm fsPackageSolarTerm = packageSolarTermMapper.selectOne(queryWrapper);
                    return Objects.nonNull(fsPackageSolarTerm)
                            && LocalDateTime.now().isAfter(fsPackageSolarTerm.getStartTime())
                            && LocalDateTime.now().isBefore(fsPackageSolarTerm.getEndTime());
                }
            }
        }
        return false;
    }

    @Override
    @Transactional
    public void followAddIntegral(Long userId, Long orderId) {
        FsUser fsUser = fsUserMapper.selectFsUserByUserId(userId);
        if (fsUser != null) {
            String json = configService.selectConfigByKey("his.integral");
            IntegralConfig config = JSONUtil.toBean(json, IntegralConfig.class);
            Integer todayTotalIntegral = integralLogsMapper.selectTodayTotalIntegral(config.getIntegralTypeByOneDay(), userId);
            if (todayTotalIntegral == null) {
                todayTotalIntegral = 0;
            }
            if (todayTotalIntegral != null && todayTotalIntegral >= config.getIntegralByOneDay()) {
                return;
            }
            Long integral = config.getIntegralFollow() + 0L;
            FsUser u = new FsUser();
            u.setUserId(userId);
            u.setIntegral(fsUser.getIntegral() + integral);
            fsUserMapper.updateFsUser(u);
            logger.info("用户{}获取积分{}", fsUser.getUserId(), integral);
            //写入日志
            FsUserIntegralLogs logs = new FsUserIntegralLogs();
            logs.setIntegral(integral.longValue());
            logs.setBusinessType(4);
            logs.setUserId(userId);
            logs.setBalance(u.getIntegral());
            logs.setLogType(6);
            logs.setBusinessId(orderId.toString());
            logs.setCreateTime(new Date());
            integralLogsMapper.insertFsUserIntegralLogs(logs);

        }
    }

    @Transactional
    public void subIntegral(Long userId) {
        FsUser fsUser = fsUserMapper.selectFsUserByUserId(userId);
        if (fsUser != null && fsUser.getIntegral() != 0) {
            Long integral = fsUser.getIntegral();
            fsUser.setIntegral(0L);
            fsUserMapper.updateFsUser(fsUser);
            logger.info("用户{}扣除积分{}", fsUser.getUserId(), 0 - integral);
            FsUserIntegralLogs logs = new FsUserIntegralLogs();
            logs.setIntegral(0 - integral);
            logs.setUserId(userId);
            logs.setBalance(0L);
            logs.setLogType(7);
            logs.setCreateTime(new Date());
            integralLogsMapper.insertFsUserIntegralLogs(logs);
        }

    }

    @Override
    public FsUserFollowDoctorVO getUserFollowDoctorAndOrderId(Long userId) {
        FsUserFollowDoctorVO fsUserFollowDoctorVO = fsStoreOrderMapper.selectFsFollowDoctorIdByUserId(userId);
        if (fsUserFollowDoctorVO != null && fsUserFollowDoctorVO.getFollowDoctorId() != null) {
            Long followId = fsFollowMapper.selectFsFollowByStoreOrderId(fsUserFollowDoctorVO.getOrderId());
            fsUserFollowDoctorVO.setFollowId(followId);
        }
        return fsUserFollowDoctorVO;
    }

    @Override
    public List<FsUserVO> selectFsUserListVOByComponent(FsUserParam fsUser) {
        return fsUserMapper.selectFsUserListVOByComponent(fsUser);
    }


    @Override
    @Transactional
    public void subUserIntegral(Long userId, Long orderId, Integer orderType) {
        FsUser fsUser = fsUserMapper.selectFsUserByUserId(userId);
        if (fsUser != null) {
            FsUserIntegralLogs maps = new FsUserIntegralLogs();
            maps.setLogType(2);
            maps.setBusinessType(orderType);
            maps.setBusinessId(orderId.toString());
            List<FsUserIntegralLogs> logsList = integralLogsMapper.selectFsUserIntegralLogsList(maps);
            if (logsList.size() > 0) {
                for (FsUserIntegralLogs userLogs : logsList) {
                    fsUser.setIntegral(fsUser.getIntegral() - userLogs.getIntegral());
                    fsUserMapper.updateFsUser(fsUser);
                    logger.info("用户{}扣除积分{}", fsUser.getUserId(), userLogs.getIntegral());
                    //写入日志
                    FsUserIntegralLogs logs = new FsUserIntegralLogs();
                    logs.setIntegral(-logsList.get(0).getIntegral());
                    logs.setUserId(userId);
                    logs.setBalance(fsUser.getIntegral());
                    logs.setBusinessType(orderType);
                    logs.setLogType(4);
                    logs.setBusinessId(orderId.toString());
                    logs.setCreateTime(new Date());
                    integralLogsMapper.insertFsUserIntegralLogs(logs);
                }
            }

        }

    }

    @Override
    public FsUser selectFsUserByUnionid(String unionid) {
        return fsUserMapper.selectFsUserByUnionid(unionid);
    }

    @Override
    public List<QwFsUserVO> selectQwFsUserListVO(QwFsUserParam qwFsUserParam) {
        return fsUserMapper.selectQwFsUserListVO(qwFsUserParam);
    }


    @Override
    public R clearUserVip(Long userId) {
        FsUser user = new FsUser();
        user.setUserId(userId);
        user.setIsVip(0);
        user.setVipStartDate(null);
        user.setVipEndDate(null);
        if (fsUserMapper.updateFsUser(user) > 0) {
            return R.ok("清除成功");
        }
        return R.error("清除vip失败");
    }

    @Override
    public List<QwFsUserVO> selecQwFsUserListVO(QwFsUserParam qwFsUserParam) {
        return fsUserMapper.selecQwFsUserListVO(qwFsUserParam);
    }

    @Override
    public Boolean isEntityNull(FsUserParam param) {
        if (param == null) {
            return true; // 整个实体对象为null
        }
        Class<? extends FsUserParam> entityClass = param.getClass();
        Field[] fields = entityClass.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(param);
                if (value != null) {
                    return false; // 实体对象中有字段不为null
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return true; // 实体对象内所有字段为null
    }

    @Override
    public Long selectFsUserExportListVOCount(FsUserParam fsUser) {
        return fsUserMapper.selectFsUserExportListVOCount(fsUser);
    }

    @Override
    public FsUser selectFsUserByMpOpenId(String openId) {
        return fsUserMapper.selectFsUserByMpOpenId(openId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void setRepeatFansTag(FsUserCourseBeMemberParam param) {
        Map<String, Object> map = new HashMap<>();
        map.put("tagName", "重粉");
        List<CompanyTag> companyTags = companyTagMapper.selectCompanyTagListByMap(map);
        Long tagId;
        if (companyTags == null || companyTags.isEmpty()) {
            CompanyTag companyTag = new CompanyTag();
            companyTag.setCompanyId(param.getCompanyId());
            companyTag.setTag("重粉");
            companyTagService.insertCompanyTag(companyTag);
            tagId = companyTag.getTagId();
        } else {
            tagId = companyTags.get(0).getTagId();
        }
        //  查询
        CompanyTagUser companyTagUserParam = new CompanyTagUser();
        companyTagUserParam.setUserId(param.getUserId());
        companyTagUserParam.setTagIds(tagId.toString());
        List<CompanyTagUser> companyTagUsers = companyTagUserMapper.selectCompanyTagUserList(companyTagUserParam);
        if (companyTagUsers == null || companyTagUsers.isEmpty()) {
            CompanyTagUser companyTagUser = new CompanyTagUser();
            companyTagUser.setUserId(param.getUserId());
            companyTagUser.setCompanyId(param.getCompanyId());
            companyTagUser.setCompanyUserId(param.getCompanyUserId());
            companyTagUser.setTagIds(tagId.toString());
            companyTagUser.setCreateTime(new Date());
            companyTagUserMapper.insertCompanyTagUser(companyTagUser);
        }
    }

    @Override
    public PageInfo<FsUserPageListVO> selectFsUserPageList(FsUserPageListParam param) {
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
        if (companyUser != null && companyUser.isAdmin()) {
            param.setUserId(0L);
            param.setCompanyId(companyUser.getCompanyId());
        }
        //筛选问题
        if (StringUtils.isNotBlank(param.getCompanyUserId())) {
            param.setUserId(Long.valueOf(param.getCompanyUserId()));
        }

        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        if (param.getTagIds() != null && param.getTagIds().length > 0) {
            boolean containsZero = Arrays.asList(param.getTagIds()).contains("0");
            // 如果包含 "0"，则设置 isNullTag 为 true
            System.out.println("是否包含 0：" + containsZero + "，参数：" + Arrays.toString(param.getTagIds()));
            if (containsZero) {
                param.setIsNullTag(true);
            }
        }
        List<FsUserPageListVO> fsUserPageListVOS = fsUserMapper.selectFsUserPageList(param);


        List<SysDictData> courseProject = dictDataMapper.selectDictDataByType("sys_course_project");
        for (FsUserPageListVO fsUserPageListVO : fsUserPageListVOS) {
            if (courseProject != null && !courseProject.isEmpty()) {
                if (fsUserPageListVO.getProjectId() != null) {
                    // 项目
                    courseProject.stream()
                            .filter(c -> c.getDictValue().equals(fsUserPageListVO.getProjectId().toString()))
                            .findFirst()
                            .ifPresent(c -> fsUserPageListVO.setProjectName(c.getDictLabel()));
                }
            }
            if (StringUtils.isEmpty(fsUserPageListVO.getNickname())) {
                fsUserPageListVO.setNickname("用户暂未授权昵称");
            }

            //解密
            if(fsUserPageListVO.getPhone() != null && fsUserPageListVO.getPhone() != ""){
                if(param.getIsHidePhoneMiddle()){
                    if (fsUserPageListVO.getPhone().length()>11){
                        fsUserPageListVO.setPhone(decryptPhoneMk(fsUserPageListVO.getPhone()));
                    }else {
                        fsUserPageListVO.setPhone(fsUserPageListVO.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
                    }
                } else {
                    fsUserPageListVO.setPhone(decryptPhone(fsUserPageListVO.getPhone()));
                }

            }
        }

        return new PageInfo<>(fsUserPageListVOS);
    }

    private static StringBuilder removeRepeatFansTag(FsUserPageListVO fsUserPageListVO) {
        String tag = fsUserPageListVO.getTag();
        String[] splitTag = tag.split(",");
        StringBuilder newTag = new StringBuilder();
        for (String s : splitTag) {
            if (!"重粉".equals(s)) {
                newTag.append(s);
            }
        }
        return newTag;
    }

    @Override
    public Boolean disabledUser(String[] ids, boolean status) {
        boolean result;
        if (status) {
            // 启用
            result = fsUserMapper.batchUpdateFsUserByIds(ids, 1) > 0;
        } else {
            // 禁用
            result = fsUserMapper.batchUpdateFsUserByIds(ids, 0) > 0;
        }
        return result;
    }

    @Override
    public FsUser selectFsUserById(Long userId) {
        return fsUserMapper.selectFsUserById(userId);
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public void transfer(FsUserTransferParamDTO param) {
        Asserts.check(ObjectUtils.isNotNull(param.getSourceCompanyUserId()), "来源用户不能为空！");
        Asserts.check(ObjectUtils.isNotNull(param.getTargetCompanyUserId()), "转移用户不能为空！");
        Asserts.check(CollectionUtils.isNotEmpty(param.getUserIds()), "要转移的客户列表不能为空！");

        fsUserMapper.transferCompanyUser(param);
    }

    @Override
    public TableDataInfo selectFsUserPageListNew(FsUserPageListParam param) {
        // 找出下级销售
        String companyUserId = param.getCompanyUserId();
        if (StringUtils.isNotBlank(companyUserId)) {
            Long companyUser = Long.parseLong(companyUserId);
            Set<Long> userIds = companyUserCacheService.selectUserAllCompanyUserId(companyUser);
            if (userIds != null || userIds.size() <= 1) {
                if (param.getIsAdmin() != null && param.getIsAdmin()) {
                    List<CompanyUser> companyUsers = companyUserMapper.selectCompanyUserByCompanyId(param.getCompanyId());
                    userIds = companyUsers.stream().map(CompanyUser::getUserId).collect(Collectors.toSet());
                }
            }
            param.setCompanyUserIds(userIds);
        }

        List<FsUserPageListVO> fsUserPageListVOS = fsUserMapper.selectFsUserPageListNew(param);
        Map<Long, CompanyTag> tagMap = companyTagCacheService.queryAllTagMap();
        //获取会员的最新的看课状态和最后看课时间
        Set<Long> userIds = fsUserPageListVOS.stream().map(FsUserPageListVO::getUserId).collect(Collectors.toSet());
        List<FsUserLastCount> fsUserCourseCounts = Collections.emptyList();
        if (!userIds.isEmpty()) {
            fsUserCourseCounts = fsUserCourseCountMapper.selectUserLastCount(userIds);
        }
        Map<Long, FsUserLastCount> countMap = fsUserCourseCounts.stream().collect(Collectors.toMap(FsUserLastCount::getUserId, Function.identity()));

        for (FsUserPageListVO item : fsUserPageListVOS) {
            if (item.getCompanyUserId() != null) {
                String companyUserName = companyUserCacheService.selectCompanyUserNameUserById(item.getCompanyUserId());
                if (companyUserName != null) {
                    item.setCompanyUserNickName(companyUserName);
                }
            }
            if (item.getPhone() != null) {
                item.setPhone(ParseUtils.parsePhone(item.getPhone()));
            }
            if (item.getStatus() != null) {
                String userStatus = DictUtils.getDictLabel("user_status", String.valueOf(item.getStatus()));
                if (StringUtils.isNotBlank(userStatus)) {
                    item.setStatusText(userStatus);
                }
            }
            if (item.getUserId() != null) {
                FsUserCourseCount byUserId = fsUserCourseCountCacheService.findByUserId(item.getUserId());
                if (byUserId != null) {
                    item.setWatchCourseCount(byUserId.getWatchCourseCount());
                    item.setMissCourseCount(byUserId.getMissCourseCount());
                    item.setMissCourseStatus(byUserId.getMissCourseStatus());
                    if (StringUtils.isNotEmpty(byUserId.getPartCourseCount())) {
                        item.setPartCourseCount(new BigDecimal(byUserId.getPartCourseCount()).longValue());
                    }
//                    item.setCourseCountStatus(byUserId.getStatus());
                    item.setStopWatchDays(byUserId.getStopWatchDays());
                    item.setCompleteWatchDate(byUserId.getCompleteWatchDate());
                    item.setLastWatchDate(byUserId.getLastWatchDate());
                }
                FsUserLastCount fsUserCourseCount = countMap.get(item.getUserId());
                if (fsUserCourseCount != null) {
                    item.setCourseCountStatus(fsUserCourseCount.getStatus());
                }
                String userTagByUserId = companyTagCacheService
                        .findUserTagByUserId(item.getUserId(), item.getCompanyUserId());
                if (StringUtils.isNotEmpty(userTagByUserId)) {
                    String[] split = userTagByUserId.split(",");
                    Set<String> tagNames = new HashSet<>();
                    for (String tag : split) {
                        if (StringUtils.isNotBlank(tag)) {
                            Long tagL = Long.parseLong(tag);
                            CompanyTag companyTag = tagMap.get(tagL);
                            if (companyTag != null) {
                                tagNames.add(companyTag.getTag());
                            }
                        }
                    }
                    item.setTagIds(userTagByUserId);
                    item.setTag(String.join(",", tagNames));
                }

                // 是否宠粉
//                Integer isRepeat = qwExternalContactCacheService.selectQwIsRepeat(item.getUserId());
//                if(isRepeat != null) {
//                    item.setIsRepeat(isRepeat);
//                }
            }

            // 解密
            if (item.getPhone() != null && item.getPhone() != "") {
                if (item.getPhone().length() > 11) {
                    item.setPhone(decryptPhoneMk(item.getPhone()));
                } else {
                    item.setPhone(item.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
                }
            }

        }

        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(fsUserPageListVOS);

        rspData.setTotal(this.selectFsUserCount(param));
        return rspData;
    }

    @Override
    public Long selectFsUserCount(FsUserPageListParam param) {
        return fsUserMapper.selectFsUserPageListCount(param);
    }

    @Override
    public Long selectFsUserCount(int type, Long companyId, Long companyUserId) {
        return fsUserMapper.selectFsUserCount(type, companyId, companyUserId);
    }

    @Override
    public Map<String, Long> getUserVipCountByCompanyUserId(Long companyUserId) {
        return fsUserMapper.getUserVipCountByCompanyUserId(companyUserId);
    }

    @Override
    public FsUser selectFsUserByUnionId(String unionId) {
        return fsUserMapper.selectFsUserByUnionId(unionId);
    }

    @Override
    public UserListPageVO getUserNumber(Long userId) {
        // 判断是否是管理员
        Long companyId = null;
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
        if (companyUser != null && companyUser.isAdmin()) {
            userId = 0L;
            companyId = companyUser.getCompanyId();
        }
        List<UserListCountVO> list = fsUserMapper.getUserNumber(userId, companyId);
        Map<String, Integer> map = list.stream()
                .collect(Collectors.toMap(UserListCountVO::getStatus, UserListCountVO::getNum, (v1, v2) -> v1 + v2));
        UserListPageVO pageVO = new UserListPageVO();
        Integer normalNum = map.getOrDefault("1", 0);
        Integer smallBlackNum = map.getOrDefault("0", 0);
        Integer blackNum = map.getOrDefault("2", 0);

        // 黑名单人数加上重粉的数量，正常人数去掉重粉数量
        int repeatUserNumber = fsUserMapper.getRepeatUserNumber(userId);
        pageVO.setNumber(normalNum - repeatUserNumber);
        pageVO.setBlackNum(blackNum + repeatUserNumber);
        pageVO.setSmallBlackNum(smallBlackNum + repeatUserNumber);

        return pageVO;
    }

    @Override
    public UserDetailsVO getUserDetails(Long userId, Long fsUserId, String dateTag, Long userCompanyId) {
        UserDetailsVO countWatchCourse = fsUserMapper.getCountWatchCourse(userId, fsUserId, dateTag, userCompanyId);
        FsUserCompanyUser fsUserCompanyUser = userCompanyUserService.selectFsUserCompanyUserById(userCompanyId);

        UserDetailsVO countAnswer = fsUserMapper.getCountAnswer(fsUserCompanyUser.getCompanyUserId(), fsUserId, dateTag);
        UserDetailsVO countRedPacket = fsUserMapper.getCountRedPacket(fsUserCompanyUser.getCompanyUserId(), fsUserId, dateTag);
        UserDetailsVO vo = new UserDetailsVO();
        if (countWatchCourse != null) {
            BeanUtils.copyProperties(countWatchCourse, vo);
        }
        if (countRedPacket != null) {
            vo.setAnswerRedPacketTime(countRedPacket.getAnswerRedPacketTime());
            vo.setAnswerRedPacketAmount(countRedPacket.getAnswerRedPacketAmount());
        } else {
            vo.setAnswerRedPacketAmount(BigDecimal.ZERO);
        }
        if (countAnswer != null) {
            vo.setAnswerTime(countAnswer.getAnswerTime());
            vo.setAnswerRightTime(countAnswer.getAnswerRightTime());
        }
        return vo;
    }

    @Override
    public Integer selectFsUserByUserIds(String[] userIds, Long companyUserId) {
        return fsUserMapper.selectFsUserByUserIds(userIds, companyUserId);
    }


    @Override
    public FsUserSummaryCountVO userSummaryCount(Long userId) {
        // 判断是否是管理员
        Long companyId;
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
        if (companyUser != null && companyUser.isAdmin()) {
            userId = 0L;
            companyId = companyUser.getCompanyId();
        } else {
            companyId = null;
        }

        // 使用 CompletableFuture 异步执行两个查询

        Long finalUserId = userId;
        CompletableFuture<Integer> userTotalFuture = CompletableFuture.supplyAsync(() ->
                fsUserMapper.getUserTotal(finalUserId, companyId));

        CompletableFuture<Integer> todayNewUserFuture = CompletableFuture.supplyAsync(() ->
                fsUserMapper.getTodayNewUser(finalUserId, companyId));

        CompletableFuture<List<FsUserSummaryCountTagVO>> countTagList = CompletableFuture.supplyAsync(() ->
                fsUserMapper.countTag(finalUserId, companyId));

        // 等待查询结果并构建返回对象
        FsUserSummaryCountVO fsUserSummaryCountVO = new FsUserSummaryCountVO();
        try {
            fsUserSummaryCountVO.setUserTotal(userTotalFuture.get());
            fsUserSummaryCountVO.setTodayNewUser(todayNewUserFuture.get());
            fsUserSummaryCountVO.setTagList(countTagList.get());

        } catch (InterruptedException | ExecutionException e) {
            logger.error("异步查询用户统计数据失败", e);
            // 设置默认值
            fsUserSummaryCountVO.setUserTotal(0);
            fsUserSummaryCountVO.setTodayNewUser(0);
            fsUserSummaryCountVO.setTagList(new ArrayList<>());
        }

        return fsUserSummaryCountVO;
    }

    public FsUserSummaryCountVO userSummaryCountOld(Long userId) {
        // 开始时间
        long start = System.currentTimeMillis();
        // 判断是否是管理员
        Long companyId = null;
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
        if (companyUser != null && companyUser.isAdmin()) {
            userId = 0L;
            companyId = companyUser.getCompanyId();
        }
        long start2 = System.currentTimeMillis();
        logger.info("countUserSummary 执行耗时: {}ms", start2 - start);

        //     Integer getUserTotal(@Param("userId") Long userId, @Param("companyId") Long companyId);
        //
        //    Integer getTodayNewUser(@Param("userId") Long userId, @Param("companyId") Long companyId);


        FsUserSummaryCountVO fsUserSummaryCountVO = fsUserMapper.countUserSummary(userId, companyId);
        long start3 =System.currentTimeMillis();
        logger.info("countTag 执行耗时: {}ms", start3 - start2);
        List<FsUserSummaryCountTagVO> countTagList = fsUserMapper.countTag(userId, companyId);
        fsUserSummaryCountVO.setTagList(countTagList);

        // 结束时间
        long end = System.currentTimeMillis();
        logger.info("countUserAnswerStats 执行耗时: {}ms", end - start3);

        return fsUserSummaryCountVO;
    }

    @Override
    public FsUserStatisticsVO userStatistics(UserStatisticsCommonParam param) {
        return getUserStatistics(param);
    }

    @Override
    public FsUserStatisticsVO userStatisticsDetails(UserStatisticsCommonParam param) {
        FsUserStatisticsVO userStatisticsVO = getUserStatistics(param);

        // 判断是否是管理员
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
        if (companyUser != null && companyUser.isAdmin()) {
            param.setUserId(0L);
        }
        //统计课程数据详情，在查询统计详情的时候需要显示
        Map<String, Long> courseDetailsMap = fsUserMapper.countCourseDetailsNew(param);
        if (courseDetailsMap != null && courseDetailsMap.get("courseNum") != null && courseDetailsMap.get("videoNum") != null && courseDetailsMap.get("courseUserNum") != null) {
            userStatisticsVO.setCourseNum(Integer.parseInt(courseDetailsMap.get("courseNum").toString()))
                    .setVideoNum(Integer.parseInt(courseDetailsMap.get("videoNum").toString()))
                    .setCourseUserNum(Integer.parseInt(courseDetailsMap.get("courseUserNum").toString()));
        }
        return userStatisticsVO;
    }

    private FsUserStatisticsVO getUserStatistics2(UserStatisticsCommonParam param) {
        FsUserStatisticsVO fsUserStatisticsVO = new FsUserStatisticsVO();

        // 判断是否是管理员
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
        if (companyUser != null && companyUser.isAdmin()) {
            param.setUserId(0L);
            param.setCompanyId(companyUser.getCompanyId());
        }
        // 获取课程统计
        Map<String, Long> couserMap = fsUserMapper.countUserCourse2(param);
        if (couserMap != null) {
            //看课人数
            fsUserStatisticsVO.setCourseWatchNum(couserMap.get("courseWatchNum").intValue()).setCourseCompleteNum(couserMap.get("courseCompleteNum").intValue());

            if (couserMap.get("courseCompleteNum") != null && couserMap.get("courseWatchNum") > 0) {
                int courseCompleteRate = BigDecimal.valueOf(couserMap.get("courseCompleteNum"))
                        .divide(BigDecimal.valueOf(couserMap.get("courseWatchNum")), 2, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100))
                        .intValue();
                fsUserStatisticsVO.setCourseCompleteRate(courseCompleteRate);
            }
        }

        // 获取答题统计
        Map<String, Long> answerMap = fsUserMapper.countUserAnswer(param);
        if (answerMap != null) {
            fsUserStatisticsVO.setAnswerNum(answerMap.get("answerNum").intValue()).setAnswerRightNum(answerMap.get("answerRightNum").intValue());

            if (answerMap.get("answerRightNum") != null && answerMap.get("answerNum") > 0) {
                int answerCompleteRate = BigDecimal.valueOf(answerMap.get("answerRightNum"))
                        .divide(BigDecimal.valueOf(answerMap.get("answerNum")), 2, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100))
                        .intValue();
                fsUserStatisticsVO.setAnswerRightRate(answerCompleteRate);
            }
        }

        // 获取红包统计
        Map<String, Object> redPacketMap = fsUserMapper.countUserRedPacket(param);
        if (redPacketMap != null && redPacketMap.get("redPacketNum") != null && redPacketMap.get("redPacketAmount") != null) {
            fsUserStatisticsVO.setRedPacketNum(Integer.parseInt(redPacketMap.get("redPacketNum").toString()))
                    .setRedPacketAmount(new BigDecimal(redPacketMap.get("redPacketAmount").toString()));
        }
        return fsUserStatisticsVO;
    }

    @Override
    public List<FsUserRankingVO> userRanking(Long userId, String startTime, String endTime, String periodId, String videoId, String order, Integer type) {
        List<FsUserRankingVO> listVO = Collections.emptyList();
        // 判断是否是管理员
        Long companyId = null;
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
        if (companyUser != null && companyUser.isAdmin()) {
            userId = 0L;
            companyId = companyUser.getCompanyId();
        }
        if (type == 1) {
            //按完播率
            listVO = fsUserMapper.countUserRankingByComplete(userId, companyId, startTime, endTime, periodId, videoId, order);
        }
        if (type == 2) {
            //按正确率
            listVO = fsUserMapper.countUserRankingByRight(userId, companyId, startTime, endTime, periodId, videoId, order);
        }
        return listVO;
    }

    @Override
    public List<FsCourseRankingVO> courseRanking(Long userId, String startTime, String endTime, String periodId, String videoId, String order, Integer type) {
        // 判断是否是管理员
        Long companyId = null;
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
        if (companyUser != null && companyUser.isAdmin()) {
            userId = 0L;
            companyId = companyUser.getCompanyId();
        }
        List<FsCourseRankingVO> list = Collections.emptyList();
        if (type == 1) {
            list = fsUserMapper.countCourseRankingByComplete(userId, companyId, startTime, endTime, periodId, videoId, order);
        }
        if (type == 2) {
            list = fsUserMapper.countCourseRankingByRight(userId, companyId, startTime, endTime, periodId, videoId, order);
        }

        return list;
    }

    @Override
    public List<FsUserGraphicStatisticsVO> graphicStatistics(UserStatisticsCommonParam param) {
        FsUserStatisticsVO userStatistics = getUserStatistics(param);
        List<FsUserGraphicStatisticsVO> list = new ArrayList<>();
        list.add(new FsUserGraphicStatisticsVO("观看人数", userStatistics.getCourseWatchNum(), userStatistics.getCourseWatchNum()));
        list.add(new FsUserGraphicStatisticsVO("完播人数", userStatistics.getCourseCompleteNum(), userStatistics.getCourseCompleteNum()));
        list.add(new FsUserGraphicStatisticsVO("答题人数", userStatistics.getAnswerNum(), userStatistics.getAnswerNum()));
        list.add(new FsUserGraphicStatisticsVO("正确人数", userStatistics.getAnswerRightNum(), userStatistics.getAnswerRightNum()));
        list.add(new FsUserGraphicStatisticsVO("答题红包数", userStatistics.getRedPacketNum(), userStatistics.getRedPacketNum()));
        list.sort(Comparator.comparingInt(FsUserGraphicStatisticsVO::getValue).reversed());
        return list;
    }

    @Override
    public List<FsCourseAnalysisVO> courseAnalysis(CourseAnalysisParam param) {
        //1、查询课程视频信息
        UserCourseVideoPageParam userCourseVideoPageParam = new UserCourseVideoPageParam();
        BeanUtils.copyProperties(param, userCourseVideoPageParam);
        List<FsUserCourseVideoPageListVO> videoList = userCourseVideoMapper.selectFsUserCourseVideoPageList(userCourseVideoPageParam);

        //2、查询统计
        List<FsCourseAnalysisCountVO> courseCountList = fsUserMapper.courseAnalysisCourseCount(param);

        List<FsCourseAnalysisCountVO> redPacketCountList = fsUserMapper.courseAnalysisRedPacketCount(param);
        List<FsCourseAnalysisCountVO> answerCountList = fsUserMapper.courseAnalysisAnswerCount(param);

        //3、转化为map
        Map<Long, FsCourseAnalysisCountVO> courseMap = courseCountList.stream()
                .collect(Collectors.toMap(
                        FsCourseAnalysisCountVO::getVideoId,
                        Function.identity()
                ));
        Map<Long, FsCourseAnalysisCountVO> redPacketMap = redPacketCountList.stream()
                .collect(Collectors.toMap(
                        FsCourseAnalysisCountVO::getVideoId,
                        Function.identity()
                ));
        Map<Long, FsCourseAnalysisCountVO> answerMap = answerCountList.stream()
                .collect(Collectors.toMap(
                        FsCourseAnalysisCountVO::getVideoId,
                        Function.identity()
                ));

        //4、处理数据
        return videoList.stream().map(v -> {
            FsCourseAnalysisVO allVO = new FsCourseAnalysisVO();
            BeanUtils.copyProperties(v, allVO);

            FsCourseAnalysisCountVO countVO = new FsCourseAnalysisCountVO();
            FsCourseAnalysisCountVO courseVO = courseMap.getOrDefault(v.getVideoId(), countVO);
            FsCourseAnalysisCountVO redPacketVO = redPacketMap.getOrDefault(v.getVideoId(), countVO);
            FsCourseAnalysisCountVO answerVO = answerMap.getOrDefault(v.getVideoId(), countVO);
            //单独赋值
            countVO.setVideoId(v.getVideoId()).setCourseWatchNum(courseVO.getCourseWatchNum()).setCourseCompleteNum(courseVO.getCourseWatchNum())
                    .setCompleteRate(courseVO.getCompleteRate() != null ? courseVO.getCompleteRate() : new BigDecimal(BigInteger.ZERO));
            countVO.setRedPacketNum(redPacketVO.getRedPacketNum())
                    .setRedPacketAmount(redPacketVO.getRedPacketAmount() != null ? redPacketVO.getRedPacketAmount() : new BigDecimal(BigInteger.ZERO));
            countVO.setAnswerNum(answerVO.getAnswerNum()).setAnswerRightNum(answerVO.getAnswerRightNum())
                    .setAnswerRightRate(answerVO.getAnswerRightRate() != null ? answerVO.getAnswerRightRate() : new BigDecimal(BigInteger.ZERO));
            allVO.setCountVO(countVO);
            return allVO;
        }).collect(Collectors.toList());
    }

    @Override
    public CompanyUserSummaryCountVO companyUserSummaryCount(Long userId, String companyUserId) {
        // 判断是否是管理员
        Long companyId = null;
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
        if (companyUser != null && companyUser.isAdmin()) {
            companyUserId = String.valueOf(0);
            companyId = companyUser.getCompanyId();
        }
        CompanyUserSummaryCountVO companyUserCount = fsUserMapper.companyUserCount(companyUserId, companyId);
        CompanyUserSummaryCountVO newUserRedPacketCount = fsUserMapper.newUserRedPacketCount(companyUserId, companyId);
        CompanyUserSummaryCountVO vo = new CompanyUserSummaryCountVO();
        BeanUtils.copyProperties(companyUserCount, vo);
        vo.setUserRedPacketNum(newUserRedPacketCount.getUserRedPacketNum());
        vo.setTodayUserRedPacketAmount(newUserRedPacketCount.getTodayUserRedPacketAmount());
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Boolean> becomeMember(FsUserCourseBeMemberParam param) {
        //查询用户
        FsUser fsUser = fsUserMapper.selectFsUserById(param.getUserId());
        if (Objects.isNull(fsUser)) {
            return ResponseResult.fail(401, "当前用户信息不存在");
        }

        //判断该销售是否存在
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getCompanyUserId());
        if (Objects.isNull(companyUser)) {
            return ResponseResult.fail(405, "销售不存在");
        }
        // 通过字段值判断该销售是否允许注册会员
        if (companyUser.getIsAllowedAllRegister() != null && companyUser.getIsAllowedAllRegister() == 0) {
            return ResponseResult.fail(407, "不允许注册会员，请联系管理员");
        }

        // 逻辑调整：如果会员已经绑定了销售，直接提示，不添加重粉数据了-2025年6月16日14点53分
        // 逻辑调整：会员与销售的绑定关系通过中间表关联 /20250625 17:13
        FsUserCompanyUser userCompanyUser = userCompanyUserService.selectByUserIdAndProjectId(fsUser.getUserId(), param.getProjectId());
        if (Objects.nonNull(userCompanyUser) && !userCompanyUser.getCompanyUserId().equals(param.getCompanyUserId())) {
            return ResponseResult.fail(500, "该用户(" + fsUser.getUserId() + ")已成为其他销售会员");
        }

        // 特殊（需求设计：需要根据公司是否开启黑名单来设置会员初始化的状态）
        Company company = companyMapper.selectCompanyById(param.getCompanyId());
        // isDefaultBlack 值为1 ，表示需要加入小黑屋，否则不加
        int isDefaultBlack = company != null ? company.getFsUserIsDefaultBlack() : 0;

        // 添加关系表数据
        if (Objects.isNull(userCompanyUser)) {
            int defaultStatus = isDefaultBlack == 1 ? 0 : 1;
            userCompanyUser = userCompanyUserService.bindRelationship(param.getUserId(), param.getProjectId(), companyUser.getCompanyId(), companyUser.getUserId(), defaultStatus);
        }

        // 不为空则添加新标签
        if (Objects.nonNull(param.getTagIds()) && param.getTagIds().length > 0) {
            userProjectTagService.addUserProjectTag(userCompanyUser.getId(), Arrays.stream(param.getTagIds()).map(Long::valueOf).collect(Collectors.toList()));
        }

//        // 如果是重粉，直接打上重粉的标签
//        if(1 == fsUserCompanyUser.getIsRepeatFans()){
//            this.setRepeatFansTag(param);
//        }

        // 与im账号绑定
        if (ImTypeConfig.IMTYPE== ImTypeEnum.OPENIM){
            openIMService.checkAndImportFriend(param.getCompanyUserId(), String.valueOf(param.getUserId()));
        }

        //如果是设置了需要进入小黑屋，则需要返回提示，否则正常返回
        if (isDefaultBlack == 1) {
            return ResponseResult.fail(402, "已成功注册，待管理审核");
        }
        return ResponseResult.ok(Boolean.TRUE);
    }

    @Override
    public FsUserPageListVO selectFsUserPageListVOByUserId(Long userId) {
        FsUser fsUser = fsUserMapper.selectFsUserByUserId(userId);
        FsUserPageListVO item = new FsUserPageListVO();
        BeanUtils.copyProperties(fsUser, item);
        item.setNickname(fsUser.getNickName());
        Map<Long, CompanyTag> tagMap = companyTagCacheService.queryAllTagMap();
        if (item.getPhone() != null) {
            item.setPhone(ParseUtils.parsePhone(item.getPhone()));
        }
        String userTagByUserId = null;
        if (item.getUserId() != null && item.getCompanyUserId() != null) {
            userTagByUserId = companyTagCacheService
                    .findUserTagByUserId(item.getUserId(), item.getCompanyUserId());
        }
        if (StringUtils.isNotEmpty(userTagByUserId)) {
            String[] split = userTagByUserId.split(",");
            Set<String> tagNames = new HashSet<>();
            for (String tag : split) {
                if (StringUtils.isNotBlank(tag)) {
                    Long tagL = Long.parseLong(tag);
                    CompanyTag companyTag = tagMap.get(tagL);
                    if (companyTag != null) {
                        tagNames.add(companyTag.getTag());
                    }
                }
            }
            item.setTagIds(userTagByUserId);
            item.setTag(String.join(",", tagNames));
        }
        return item;
    }

    @Override
    @Transactional
    public void addMoney(FsStoreOrderScrm order) {
        FsUserBillScrm map = new FsUserBillScrm();
        map.setCategory(CATEGORY_3.getValue());
        map.setBusinessId(order.getId().toString());
        map.setBillType(1);
        List<FsUserBillScrm> list = billService.selectFsUserBillList(map);
        if (list != null && list.size() > 0) {
            for (FsUserBillScrm bill : list) {
                FsUser tuiUser = fsUserMapper.selectFsUserByIdForUpdate(bill.getUserId());
                if (tuiUser != null) {
                    FsUser tuiUserMap = new FsUser();
                    tuiUserMap.setUserId(tuiUser.getUserId());
                    tuiUserMap.setNowMoney(tuiUser.getNowMoney().add(bill.getMoney()));
                    tuiUserMap.setBrokeragePrice(tuiUser.getBrokeragePrice().subtract(bill.getMoney()));
                    fsUserMapper.updateFsUser(tuiUserMap);
                    billService.addBill(tuiUserMap.getUserId(), CATEGORY_3.getValue(), 0, BillDetailEnum.TYPE_6.getDesc(), bill.getMoney(), tuiUserMap.getBrokeragePrice(), "订单分佣金", order.getId().toString(), bill.getTuiUserId());
                    billService.addBill(tuiUserMap.getUserId(), CATEGORY_1.getValue(), 1, BillDetailEnum.TYPE_5.getDesc(), bill.getMoney(), tuiUserMap.getNowMoney(), "订单分佣金", order.getId().toString(), bill.getTuiUserId());
                }
            }
        }
        FsStoreOrderScrm orderMap = new FsStoreOrderScrm();
        orderMap.setId(order.getId());
        orderMap.setTuiUserMoneyStatus(1);
        storeOrderMapper.updateFsStoreOrder(orderMap);
    }

    @Override
    public R updateStatus(Long userId) {
        fsUserMapper.updateUserStatus(userId);
        return R.ok();
    }

    @Override
    public List<FsUserVO> selectFsUserVOListByProject(FsUser fsUser) {
        return fsUserMapper.selectFsUserVOListByProject(fsUser);
    }

    /**
     * @Description: 原方法 selectFsUserVOListByProject sql执行太慢，优化修改
     * @Param:
     * @Return:
     * @Author xgb
     * @Date 2025/11/10 10:34
     */
    @Override
    public List<FsUserVO> selectFsUserVOListByProjectNew(FsUser fsUser) {

        List<FsUserVO>  list=fsUserMapper.selectFsUserVOListByProjectNew(fsUser);
        if(list!=null && !list.isEmpty()){
            // 查询看课数和最后看课时间
            Set<Long> userIds = list.stream().map(FsUserVO::getUserId).collect(Collectors.toSet());
            List<FsUserCourseCount> fsUserCourseCounts = fsUserCourseCountMapper.selectUserLastCountList(userIds);
            Map<Long, FsUserCourseCount> courseCountMap = fsUserCourseCounts.stream()
                    .collect(Collectors.toMap(FsUserCourseCount::getUserId, Function.identity()));

            list.forEach(item -> {
                FsUserCourseCount courseCount = courseCountMap.get(item.getUserId());
                if (courseCount != null) {
                    item.setLastWatchDate(courseCount.getLastWatchDate());
                    item.setWatchCourseCount(courseCount.getWatchCourseCount());
                }
            });
        }
        return list;
    }

    @Override
    public FsUserAndCompanyAndDoctorVo selectCompanyAndDoctor(Long userId) {
        return fsUserMapper.selectCompanyAndDoctor(userId);
    }

    @Override
    public List<FsUser> selectUserByIds(String userIds) {
        return fsUserMapper.selectUserNameByIds(userIds);
    }

    @Override
    public List<FsUser> selectFsUserListByJointUserNameKey(String userNameKey) {
        return fsUserMapper.selectFsUserListByJointUserNameKey(userNameKey);
    }


    /**
     * @Description: 该方法原方法是 getUserStatisticsOld
     * 目的为了优化sql查询 fsUserMapper.countUserStats 现拆分成三次异步查询
     * @Param:
     * @Return:
     * @Author xgb
     * @Date 2025/10/29 15:34
     */
    private FsUserStatisticsVO getUserStatistics(UserStatisticsCommonParam param) {

        FsUserStatisticsVO fsUserStatisticsVO = new FsUserStatisticsVO();

        // 判断是否是管理员
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
        if (companyUser != null && companyUser.isAdmin()){
            param.setUserId(0L);
            param.setCompanyId(companyUser.getCompanyId());
        }

        // 异步调用三个查询方法
        CompletableFuture<Map<String, Object>> watchStatsFuture = CompletableFuture.supplyAsync(() ->
                fsUserMapper.countUserWatchStats(param));

        CompletableFuture<Map<String, Object>> answerStatsFuture = CompletableFuture.supplyAsync(() ->
                fsUserMapper.countUserAnswerStats(param));

        CompletableFuture<Map<String, Object>> redPacketStatsFuture = CompletableFuture.supplyAsync(() ->
                fsUserMapper.countUserRedPacketStats(param));

        try {
            // 等待所有查询完成
            Map<String, Object> watchMap = watchStatsFuture.get();
            Map<String, Object> answerMap = answerStatsFuture.get();
            Map<String, Object> redPacketMap = redPacketStatsFuture.get();

            // 处理观看和完成人数统计
            if (watchMap != null) {
                fsUserStatisticsVO.setCourseWatchNum(Integer.valueOf(watchMap.getOrDefault("courseWatchNum", 0L).toString()))
                        .setCourseCompleteNum(Integer.valueOf(watchMap.getOrDefault("courseCompleteNum", 0L).toString()));

                Long completeNum = (Long) watchMap.get("courseCompleteNum");
                Long watchNum = (Long) watchMap.get("courseWatchNum");
                if (completeNum != null && watchNum != null && watchNum > 0) {
                    int courseCompleteRate = BigDecimal.valueOf(completeNum)
                            .divide(BigDecimal.valueOf(watchNum), 2, RoundingMode.HALF_UP)
                            .multiply(BigDecimal.valueOf(100))
                            .intValue();
                    fsUserStatisticsVO.setCourseCompleteRate(courseCompleteRate);
                }
            }

            // 处理答题统计
            if (answerMap != null) {
                Long answerRightNum = (Long) answerMap.get("answerRightNum");
                Long answerNum = (Long) answerMap.get("answerNum");

                fsUserStatisticsVO.setAnswerNum(answerNum.intValue()).setAnswerRightNum(answerRightNum.intValue());

                if (answerRightNum != null && answerNum != null && answerNum > 0) {
                    int answerCompleteRate = BigDecimal.valueOf(answerRightNum)
                            .divide(BigDecimal.valueOf(answerNum), 2, RoundingMode.HALF_UP)
                            .multiply(BigDecimal.valueOf(100))
                            .intValue();
                    fsUserStatisticsVO.setAnswerRightRate(answerCompleteRate);
                }
            }

            // 处理红包统计
            if (redPacketMap != null) {
                Object numObj = redPacketMap.get("redPacketNum");
                Object amtObj = redPacketMap.get("redPacketAmount");
                if (numObj != null && amtObj != null) {
                    fsUserStatisticsVO.setRedPacketNum(Integer.parseInt(numObj.toString()))
                            .setRedPacketAmount(new BigDecimal(amtObj.toString()));
                }
            }
        } catch (InterruptedException | ExecutionException e) {
            // 异常处理
            logger.error("异步查询用户统计数据失败", e);
        }

        return fsUserStatisticsVO;
    }




    private FsUserStatisticsVO getUserStatisticsNew(UserStatisticsCommonParam param) {
        FsUserStatisticsVO fsUserStatisticsVO = new FsUserStatisticsVO();

        // 判断是否是管理员
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
        if (companyUser != null && companyUser.isAdmin()){
            param.setUserId(0L);
            param.setCompanyId(companyUser.getCompanyId());
        }


        Map<String, Object> map = fsUserMapper.countUserStats(
                param
        );
        // 获取课程统计
//        Map<String, Long> courseMap = fsUserMapper.countUserCourse2(param);
        if (map != null) {
            fsUserStatisticsVO.setCourseWatchNum(Integer.valueOf(map.getOrDefault("courseWatchNum", 0L).toString()))
                    .setCourseCompleteNum(Integer.valueOf(map.getOrDefault("courseCompleteNum", 0L).toString()));

            Long completeNum = (Long) map.get("courseCompleteNum");
            Long watchNum = (Long) map.get("courseWatchNum");
            if (completeNum != null && watchNum != null && watchNum > 0) {
                int courseCompleteRate = BigDecimal.valueOf(completeNum)
                        .divide(BigDecimal.valueOf(watchNum), 2, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100))
                        .intValue();
                fsUserStatisticsVO.setCourseCompleteRate(courseCompleteRate);
            }
        }

        // 获取答题统计
//        Map<String, Long> answerMap = fsUserMapper.countUserAnswer(param);
        if (map != null) {
            Long answerRightNum = (Long) map.get("answerRightNum");
            Long answerNum = (Long) map.get("answerNum");

            fsUserStatisticsVO.setAnswerNum(answerNum.intValue()).setAnswerRightNum(answerRightNum.intValue());

            if (answerRightNum != null && answerNum != null && answerNum > 0) {
                int answerCompleteRate = BigDecimal.valueOf(answerRightNum)
                        .divide(BigDecimal.valueOf(answerNum), 2, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100))
                        .intValue();
                fsUserStatisticsVO.setAnswerRightRate(answerCompleteRate);
            }
        }

        // 获取红包统计
//        Map<String, Object> redPacketMap = fsUserMapper.countUserRedPacket(param);
        if (map != null) {
            Object numObj = map.get("redPacketNum");
            Object amtObj = map.get("redPacketAmount");
            if (numObj != null && amtObj != null) {
                fsUserStatisticsVO.setRedPacketNum(Integer.parseInt(numObj.toString()))
                        .setRedPacketAmount(new BigDecimal(amtObj.toString()));
            }
        }
        return fsUserStatisticsVO;
    }

    private static FsUserCompanyUser getFsUserCompanyUser(FsUserCourseBeMemberParam param, FsUser fsUser) {
        FsUserCompanyUser fsUserCompanyUser = new FsUserCompanyUser();
        // 判断是否绑定了销售，如果已绑定，则需要标识为重粉，且放黑名单
        if (fsUser.getCompanyUserId() != null && !fsUser.getCompanyUserId().equals(param.getCompanyUserId())) {
            fsUserCompanyUser.setIsRepeatFans(1);
        } else {
            fsUserCompanyUser.setIsRepeatFans(0);
        }
        fsUserCompanyUser.setUserId(param.getUserId());
        fsUserCompanyUser.setCompanyId(param.getCompanyId());
        fsUserCompanyUser.setCompanyUserId(param.getCompanyUserId());
        return fsUserCompanyUser;
    }

    @Override
    public List<FsCompanyUserListQueryVO> selectFsCompanyUserListQuery(FsUser fsUser) {
        return fsUserMapper.selectFsCompanyUserListQuery(fsUser);
    }

    @Override
    public List<FsUser> getUserListLimit(FsUser fsUser) {
        return fsUserMapper.selectFsUserListLimit(fsUser);
    }

    @Override
    public void handleFsUserWx(FsUser user, LoginMaWxParam param, WxMaJscode2SessionResult session) {
        if (user == null) return;
        // 尝试更新
        boolean updated = fsUserWxService.lambdaUpdate()
                .eq(FsUserWx::getFsUserId, user.getUserId())
                .eq(FsUserWx::getAppId, param.getAppId())
                .eq(FsUserWx::getOpenId, session.getOpenid())
                .set(FsUserWx::getCompanyId, param.getCompanyId())
                .set(FsUserWx::getUnionId, session.getUnionid() == null ? "" : session.getUnionid())
                .set(FsUserWx::getUpdateTime, new Date())
                .update();

        // 如果更新失败（记录不存在），则插入
        if (!updated) {
            FsUserWx fsUserWx = new FsUserWx();
            fsUserWx.setType(1);
            fsUserWx.setFsUserId(user.getUserId());
            fsUserWx.setCompanyId(param.getCompanyId());
            fsUserWx.setAppId(param.getAppId());
            fsUserWx.setOpenId(session.getOpenid());
            fsUserWx.setUnionId(session.getUnionid() == null ? "" : session.getUnionid());
            fsUserWx.setCreateTime(new Date());
            fsUserWx.setUpdateTime(new Date());
            fsUserWxService.save(fsUserWx);
        }
    }

    @Override
    public R removeUser(Long id) {
        fsUserMapper.removeUser(id);
        return R.ok();
    }



    @Override
    public void increaseIntegral(List<Long> userIds, Long scoreAmount) {
        fsUserMapper.incrIntegral(userIds, scoreAmount);
    }

    @Override
    public HisFsUserVO getHisUserIntegralWithLogs(FsUser fsUser) {
//        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
//            JSONObject param = new JSONObject();
//            param.put("userId", user.getUserId());
//            param.put("phone", user.getPhone());
//            param.put("unionId", user.getUnionId());
//            CryptoUtil.SignedData signedData = CryptoUtil.encryptAndSignRequest(param.toString());
//            HttpPost httpPost = new HttpPost(getHisUserIntegralWithLogs);
//            String jsonString = JSONObject.toJSONString(signedData);
//
//            // 设置请求体和请求头
//            StringEntity entity = new StringEntity(jsonString, "UTF-8");
//            httpPost.setEntity(entity);
//            httpPost.setHeader("Content-Type", "application/json");
//            httpPost.setHeader("Accept", "application/json");
//
//            // 发送请求并获取响应
//            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
//                String string = EntityUtils.toString(response.getEntity(), "UTF-8");
//                if(com.fs.common.utils.StringUtils.isNotBlank(string)){
//                    JSONObject responseObj = JSONObject.parseObject(string);
//                    if(responseObj.containsKey("code") && "200".equals(responseObj.getString("code"))){
//                        String data = responseObj.getString("data");
//                        CryptoUtil.SignedData responseSignedData = JSONObject.parseObject(data, CryptoUtil.SignedData.class);
//                        String s = CryptoUtil.decryptAndVerifyResponse(responseSignedData);
//                        HisFsUserVO hisFsUserVO = JSONObject.parseObject(s, HisFsUserVO.class);
//                        return hisFsUserVO;
//                    }
//                    return new HisFsUserVO();
//                }
//                return new HisFsUserVO();
//            } catch (ClientProtocolException e) {
//                throw new RuntimeException(e);
//            } catch (IOException e) {
//                throw new RuntimeException(e);
//            }
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
        return new HisFsUserVO();
    }

}
