package com.fs.app.controller;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import com.fs.app.annotation.Login;
import com.fs.app.param.*;
import com.fs.app.utils.JsonUtils;
import com.fs.app.utils.WxUtil;
import com.fs.common.VerifyCodeUtil;
import com.fs.common.annotation.RepeatSubmit;
import com.fs.common.core.domain.R;
import com.fs.common.core.redis.RedisCache;
import com.fs.common.exception.ServiceException;
import com.fs.common.service.ISmsService;
import com.fs.common.utils.ServletUtils;
import com.fs.common.utils.ip.IpUtils;
import com.fs.common.utils.sign.Md5Utils;
import com.fs.core.config.WxOpenProperties;
import com.fs.his.config.FsSysConfig;
import com.fs.his.domain.FsUser;
import com.fs.his.domain.FsUserNewTask;
import com.fs.his.mapper.FsUserMapper;
import com.fs.his.service.IAppUserRewardService;
import com.fs.his.service.IFsUserNewTaskService;
import com.fs.his.service.IFsUserService;
import com.fs.his.utils.ConfigUtil;
import com.fs.his.vo.FsUserRegisterParam;
import com.fs.watch.domain.WatchDeviceSetup;
import com.fs.watch.domain.WatchUser;
import com.fs.watch.service.WatchUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.fs.his.utils.PhoneUtil.encryptPhone;
import static com.fs.his.utils.PhoneUtil.encryptPhoneOldKey;

@Api("app登录接口")
@RestController
@RequestMapping(value="/app/app")
@Slf4j
public class AppLoginController extends AppBaseController{
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private IFsUserService userService;
    @Autowired
    private FsUserMapper userMapper;
    @Autowired
    private IFsUserNewTaskService userNewTaskService;
    @Autowired
    private WxOpenProperties openProperties;

    @Autowired
    private ISmsService smsService;

    @Autowired
    private IAppUserRewardService appUserRewardService;

    @Autowired
    private RedisCache redisCache;
    @ApiOperation("注册app用户")
    @PostMapping("/register")
    @RepeatSubmit
    public R registerDoctor(@Validated @RequestBody FsUserRegisterParam param){
        FsUser fsUser = findUserByPhone(param.getPhone());

//        if (fsUser == null) {
//            // 尝试使用加密后的手机号查询
//            fsUser = userService.selectFsUserByPhone(encryptPhone(param.getPhone()));
//        }

        if (fsUser != null && StringUtils.isNotEmpty(fsUser.getPassword())) {
            return R.error("此账号已经注册");
        }

        FsUser user = new FsUser();
        if (fsUser != null) {
            // 更新已有用户的密码
            user.setUserId(fsUser.getUserId());
            user.setPassword(Md5Utils.hash(param.getPassword()));
            user.setUpdateTime(new DateTime());
            userService.updateFsUser(user);
            return R.ok("注册成功");
        } else {
            // 创建新用户
            user.setPhone(param.getPhone());
            user.setNickName("app用户" + param.getPhone().substring(param.getPhone().length() - 4));
            user.setStatus(1);
            user.setAvatar("https://cos.his.cdwjyyh.com/fs/20240926/420728ee06e54575ba82665dedb4756b.png");
            user.setPassword(Md5Utils.hash(param.getPassword()));
            user.setCreateTime(new Date());

            if (userService.insertFsUser(user) > 0) {
                return R.ok("注册成功");
            } else {
                return R.error("注册失败");
            }
        }

    }

    @ApiOperation("登录")
    @PostMapping("/login")
    @Transactional
    public R login(@Validated @RequestBody FsUserLoginParam param) {
        int loginType = param.getLoginType();
        switch (loginType) {
            case 1:
                return handleLoginType1(param);
            case 3:
                return handleLoginType3(param);
            default:
                return R.error("请选择正确的登陆类型！");
        }
    }


    @PostMapping("/registerSendCode")
    public R registerSendCode(@RequestBody Map<String, String> body){
        String phone = body.get("phone");
        String encryptPhone = encryptPhone(phone);
        List<FsUser> user = userService.selectFsUserListByPhone(encryptPhone);
        if(CollectionUtil.isEmpty(user)){
            user = userService.selectFsUserListByPhone(encryptPhoneOldKey(phone));
            if (CollectionUtils.isEmpty(user)){
                user=userService.selectFsUserListByPhone(phone);//如果加密后的电话号码没有搜到就直接用号码搜索
            }
        }
        if (!CollectionUtil.isEmpty(user)){
            return R.error("此电话号码已注册");
        }

        // 验证码 key（存验证码，3分钟有效）
        String smsCodeKey = "sms:code:" + phone;
        // 发送冷却 key（限制60秒内不能再次发送）
        String smsCooldownKey = "sms:cooldown:" + phone;

        // 判断是否在60秒冷却时间内
        if (redisCache.getCacheObject(smsCooldownKey) != null) {
            return R.error("验证码已发送，请稍后再试");
        }

        // 生成新的验证码
        String smsCode = VerifyCodeUtil.generateCode();

        // 发送短信
        smsService.sendCaptcha(phone, smsCode, "验证码");

        // 缓存验证码（3分钟有效）
        redisCache.setCacheObject(smsCodeKey, smsCode, 180, TimeUnit.SECONDS);
        // 设置冷却时间（60秒内不能再发）
        redisCache.setCacheObject(smsCooldownKey, "1", 60, TimeUnit.SECONDS);

        return R.ok("验证码已发送");
    }


    @PostMapping("/registerByPhone")
    public R registerByPhone(@RequestBody Map<String,String> map){
        String phone = map.get("phone");
        String code = map.get("code");
        String password = map.get("password");
        String encryptPhone = encryptPhone(phone);
        List<FsUser> users = userService.selectFsUserListByPhone(encryptPhone);
        if (users == null || CollectionUtil.isEmpty(users)){
            String s = encryptPhoneOldKey(phone);
            users = userService.selectFsUserListByPhone(s);
            if (CollectionUtils.isEmpty(users)){
                users=userService.selectFsUserListByPhone(phone);//如果加密后的电话号码没有搜到就直接用号码搜索
            }
        }
        if (!CollectionUtil.isEmpty(users)){
            return R.error("此账号已经注册");
        }
        String redisCode = redisCache.getCacheObject("sms:code:" + phone);
        if (StringUtils.isEmpty(redisCode)){
            return R.error("验证码已过期，请重新发送");
        }
        if (!redisCode.equals(code)) {
            return R.error("验证码错误");
        }
        FsUser user = new FsUser();
        // 创建新用户
        user.setPhone(phone);
        user.setJpushId(map.get("jpushId"));
        user.setSource(map.get("source"));
        user.setNickName("app用户" + phone.substring(phone.length() - 4));
        user.setStatus(1);
        user.setAvatar("https://cos.his.cdwjyyh.com/fs/20240926/420728ee06e54575ba82665dedb4756b.png");
        user.setPassword(Md5Utils.hash(password));
        user.setCreateTime(new Date());
        if (userService.insertFsUser(user) > 0) {
            return R.ok("注册成功");
        } else {
            return R.error("注册失败");
        }
    }





    @ApiOperation("找回密码")
    @PostMapping("/editPwd")
    public R login(@Validated @RequestBody FsUserEditPwdParam param) {
        FsUser user = userService.selectFsUserByPhone(encryptPhone(param.getPhone()));
        if (user==null){
            return R.error("用户不存在");
        }
        String code = redisCache.getCacheObject(user.getPhone());
        if(StringUtils.isEmpty(code)){
            return R.error("验证码已过期");
        }
        if(!code.equals(param.getCode())){
            return R.error("验证码不正确");
        }
        FsUser userMap=new FsUser();
        userMap.setUserId(user.getUserId());
        userMap.setPassword(Md5Utils.hash(param.getPassword()));
        if (userService.updateFsUser(userMap)>0){
            return R.ok("新密码设置成功");
        }
        return R.error("新密码设置失败，请稍后再试！");
    }


    @ApiOperation("微信登录")
    @PostMapping("/loginByWeChat")
    @Transactional
    public R loginByWeChat(@Validated @RequestBody FsUserLoginByWeChatParam param) {
        try {
            if (StringUtils.isBlank(param.getCode())) {
                return R.error("code不存在");
            }
            logger.info("zyp app微信登录，param:{}，输出appid，{}，secret：{}", param, openProperties.getAppId(), openProperties.getSecret());
            Map result = WxUtil.getAccessToken(param.getCode(), openProperties.getAppId(), openProperties.getSecret());
            String accessToken = result.get("access_token").toString();
            String unionid = result.get("unionid").toString();

            String openid = result.get("openid").toString();

            Map userInfo = WxUtil.getUserInfo(accessToken, openid);

            String nickname = userInfo.get("nickname").toString();
            Integer sex = (Integer) userInfo.get("sex");
            String avatar = userInfo.get("headimgurl").toString();
            FsUser user = userService.selectFsUserByUnionid(unionid);

            Map<String, Object> map = new HashMap<>();
            if (user == null) {
                user = new FsUser();
                user.setAppOpenId(openid);//设置appOpenId
                user.setLoginDevice(param.getLoginDevice()!=null ? param.getLoginDevice() : null);
                user.setSource(param.getSource()!=null ? param.getSource() : null);
                user.setNickName(nickname);
                user.setAvatar(avatar);
                if (sex!=0){
                    user.setSex(sex);
                }
                user.setUnionId(unionid);
                user.setCreateTime(new Date());
                user.setStatus(1);
                if (StringUtils.isNotEmpty(param.getJpushId())) {
                    user.setJpushId(param.getJpushId());
                }
                userService.insertFsUser(user);
                map.put("isNew", true);
                map.put("unionid",unionid);
                return R.ok(map);
            } else {
                if (StringUtils.isNotEmpty(param.getJpushId())) {
                    user.setAppOpenId(openid);//设置appOpenId
                    updateExistingUserJpushId(user, param.getJpushId());
                }
                if (StringUtils.isEmpty(user.getPhone())) {
                    FsUser userMap = new FsUser();
                    userMap.setUserId(user.getUserId());
                    userMap.setAppOpenId(user.getAppOpenId());
                    userService.updateFsUser(userMap);
                    map.put("isNew", true);
                    map.put("unionid",user.getUnionId());
                    return R.ok(map);
                }
            }
            int isFirstLogin = userNewTaskService.performTaskOne(user.getUserId());
            String token = jwtUtils.generateToken(user.getUserId());
            redisCache.setCacheObject("userToken:" + user.getUserId(), token, 604800, TimeUnit.SECONDS);
            map.put("token", token);
            map.put("user", user);
            map.put("isFirst",isFirstLogin);
            return R.ok(map);
        }catch (Exception e){
            logger.error("zyp 登录失败:{}", e.getMessage());
            return R.error("登录失败");
        }

    }

    @ApiOperation("苹果登录")
    @PostMapping("/loginByApple")
    @Transactional
    public R loginByApple(@Validated @RequestBody FsUserLoginByAppleParam param) {
        try {
            if (StringUtils.isEmpty(param.getAppleKey())) {
                return R.error("获取苹果key失败");
            }
            // 根据苹果key查询用户
            FsUser user = userMapper.findUserByAppleKey(param.getAppleKey());
            Map<String, Object> map = new HashMap<>();
            if (user == null) {
                map.put("isNew", true);
                return R.ok(map);
            } else {
                if (user.getStatus()==0&&StringUtils.isNotEmpty(param.getSource())&&!param.getSource().equals("iOS")){
                    return R.error("登录失败,账户被禁用");
                }
                if (StringUtils.isNotEmpty(param.getJpushId())) {
                    updateExistingUserJpushId(user, param.getJpushId());
                }
                if (StringUtils.isEmpty(user.getPhone())) {
                    map.put("isNew", true);
                    return R.ok(map);
                }
            }
            /*if (user.getStatus()==0){
                return R.error("登录失败,账户被禁用");
            }*/
            int isFirstLogin = userNewTaskService.performTaskOne(user.getUserId());
            String token = jwtUtils.generateToken(user.getUserId());
            redisCache.setCacheObject("userToken:" + user.getUserId(), token, 604800, TimeUnit.SECONDS);
            map.put("token", token);
            map.put("user", user);
            map.put("isFirst",isFirstLogin);
            return R.ok(map);
        }catch (Exception e){
            logger.error("zyp 苹果登录失败:{}", e.getMessage());
            return R.error("登录失败");
        }
    }

    private FsUser createNewAppleUser(FsUserEditPhoneParam param, String phoneNumber) {
        FsUser newUser = new FsUser();
        newUser.setLoginDevice(param.getLoginDevice()!=null ? param.getLoginDevice() : null);
        newUser.setSource(param.getSource()!=null ? param.getSource() : null);
        newUser.setHistoryApp("app");
        newUser.setAppleKey(param.getAppleKey());
        newUser.setPhone(param.getPhone());
        newUser.setPassword(Md5Utils.hash(param.getPassword()));
        newUser.setNickName("苹果用户" + param.getPhone().substring(param.getPhone().length() - 4));
        newUser.setCreateTime(new Date());
        newUser.setStatus(1);
        newUser.setAvatar("https://cos.his.cdwjyyh.com/fs/20240926/420728ee06e54575ba82665dedb4756b.png");
        if (StringUtils.isNotEmpty(param.getJpushId())) {
            newUser.setJpushId(param.getJpushId());
        }
        userService.insertFsUser(newUser);
        return newUser;

    }

    @ApiOperation("绑定手机号")
    @PostMapping("/setIPhoneNumber")
    public R setIPhoneNumber(@Validated @RequestBody FsUserEditPhoneParam param) {
        FsUser userMap = findUserByPhone(param.getPhone());
        if (userMap==null) {
            //加密手机号查询
            userMap = findUserByPhone(encryptPhone(param.getPhone()));
        }
        if (userMap != null) {
            if (StringUtils.isNotEmpty(userMap.getAppleKey()) && !param.getAppleKey().equals(userMap.getAppleKey())) {
                return R.error("该手机号已绑定其他账号");
            }
            if (param.getSimExist() == 0 && !Md5Utils.hash(param.getPassword()).equals(userMap.getPassword())) {
                return R.error("密码不正确");
            }
        } else {
            userMap = createNewAppleUser(param, param.getPhone());
        }

        userMap.setLoginDevice(param.getLoginDevice());
        userMap.setHistoryApp("app");
        userMap.setSource(param.getSource());
        if (userMap.getNickName().equals("匿名用户**")) {
            userMap.setNickName("苹果用户" + param.getPhone().substring(param.getPhone().length() - 4));
        }
        userMap.setAppleKey(param.getAppleKey());
        if (userService.updateFsUser(userMap)>0){
            return generateTokenAndReturn(userMap);
        }
        return R.error("绑定手机号失败");
    }

    @PostMapping("/loginByPhone")
    public R loginByPhone(@RequestBody Map<String,String> map){
        logger.info("短信登录参数：{}",map.toString());
        String phone = map.get("phone");
        String code = map.get("code");
        String encryptPhone = encryptPhone(phone);
        List<FsUser> user;
        user = userService.selectFsUserListByPhone(encryptPhone);
        logger.info("加密手机号查询用户列表数据：{}", JsonUtils.toJson(user));
        if (CollectionUtil.isEmpty(user)){
            user = userService.selectFsUserListByPhone(encryptPhoneOldKey(phone));
            if (CollectionUtils.isEmpty(user)){
                user=userService.selectFsUserListByPhone(phone);//如果加密后的电话号码没有搜到就直接用号码搜索
            }
            logger.info("加密手机号查询用户列表数据----1>：{}", JsonUtils.toJson(user));
        }
        if (CollectionUtil.isEmpty(user)){
            return R.error("此电话号码未绑定用户");
        }
        if (user.size()>1){
            //如果出现了一个手机号多个用户的情况，找出登陆过app的那个用户
            user.removeIf(fsUser -> StringUtils.isEmpty(fsUser.getHistoryApp()));
            logger.info("历史数据用户>：{}", JsonUtils.toJson(user));
        }
        String redisCode = redisCache.getCacheObject("sms:code:" + phone);
        if (StringUtils.isEmpty(redisCode)){
            return R.error("验证码已过期，请重新发送");
        }
        if (!redisCode.equals(code)) {
            return R.error("验证码错误");
        }
        updateExistingUserJpushId(user.get(0), map.get("jpushId"));
        return generateTokenAndReturn(user.get(0));
    }

    @PostMapping("/resetPassword")
    public R resetPassword(@RequestBody Map<String, String> body){
        String phone = body.get("phone");
        String code = body.get("code");
        String newPassword = body.get("newPassword");
        String confirmPassword = body.get("confirmPassword");
        if (!newPassword.equals(confirmPassword)){
            throw new ServiceException("两次输入密码不一致，请检查");
        }
        String encryptPhone = encryptPhone(phone);
        List<FsUser> user = userService.selectFsUserListByPhone(encryptPhone);
        if (CollectionUtil.isEmpty(user)){
            user = userService.selectFsUserListByPhone(encryptPhoneOldKey(phone));
            if (CollectionUtil.isEmpty(user)){
                user = userService.selectFsUserListByPhone(phone);
            }
        }
        if (CollectionUtil.isEmpty(user)){
            return R.error("此电话号码未绑定用户");
        }
        String redisCode = redisCache.getCacheObject("sms:code:" + phone);
        if (StringUtils.isEmpty(redisCode)){
            return R.error("验证码已过期，请重新发送");
        }
        if (!redisCode.equals(code)) {
            return R.error("验证码错误");
        }
        String password = Md5Utils.hash(newPassword);
        return userService.updatePasswordByPhone(password,encryptPhone);
    }

    @ApiOperation("绑定手机号")
    @PostMapping("/setPhone")
    public R setPhone(@Validated @RequestBody FsUserEditPhoneParam param) {
        logger.info("fcj 绑定手机号入参:{}", param);
        FsUser user = userService.selectFsUserByUnionid(param.getUnionId());
        if (user==null){
            return R.error("用户数据不存在");
        }
        FsUser userMap = findUserByPhone(param.getPhone());
//        if (userMap!=null){
//            return R.error("该手机号已绑定其他账号");
//        }
        user.setPhone(param.getPhone());
        user.setLoginDevice(param.getLoginDevice() != null ? param.getLoginDevice() : null );
        user.setSource(param.getSource()!= null ? param.getSource() : null);
        userMap = new FsUser();
        userMap.setLoginDevice(param.getLoginDevice());
        userMap.setSource(param.getSource());
        userMap.setUserId(user.getUserId());
        userMap.setPhone(param.getPhone());
        if (userService.updateFsUser(userMap)>0){
            return generateTokenAndReturn(user);
        }
        return R.error("绑定手机号失败");
    }

    @ApiOperation("绑定微信")
    @PostMapping("/bindWeChat")
    public R bindWeChat(@Validated @RequestBody FsUserEditUnionidParam param) {
        try {
            logger.info("zyp app绑定微信，param:{}", param);
            Map result = WxUtil.getAccessToken(param.getCode(), openProperties.getAppId(), openProperties.getSecret());
            String accessToken = result.get("access_token").toString();
            String unionid = result.get("unionid").toString();
            String openid = result.get("openid").toString();
            Map userInfo = WxUtil.getUserInfo(accessToken, openid);
            String nickname = userInfo.get("nickname").toString();
            Integer sex = (Integer) userInfo.get("sex");
            String avatar = userInfo.get("headimgurl").toString();
            FsUser user = findUserByPhone(param.getPhone());
            if (user!=null && StringUtils.isEmpty(user.getUnionId())){
                FsUser userByUnionId = userMapper.selectFsUserByUnionid(unionid);
//                if (userByUnionId!=null){
//                    return R.error("该微信已绑定其他用户,请勿重复绑定!");
//                }
                user.setSource(param.getSource() != null ? param.getSource() : null );
                user.setLoginDevice(param.getLoginDevice() != null ? param.getLoginDevice() : null);
                user.setNickName(nickname);
                user.setAvatar(avatar);
                user.setSex(sex);
                user.setUnionId(unionid);
                if(StringUtils.isEmpty(user.getAppOpenId())){
                    user.setAppOpenId(openid);
                }
                String ipAddr = IpUtils.getIpAddr(ServletUtils.getRequest());
                user.setLastIp(ipAddr);
                if (userService.updateFsUser(user)>0){
                    return generateTokenAndReturn(user);
                }
//                else {
//                    return R.error("绑定微信失败");
//                }
            }
            return R.error("数据参数异常！");
        }catch (Exception e){
            logger.error("zyp 登录失败:{}", e.getMessage());
            return R.error("登录失败");
        }
    }

    private void updateExistingUserJpushId(FsUser user, String jpushId) {
        FsUser userMap = new FsUser();
        userMap.setUserId(user.getUserId());
        userMap.setJpushId(jpushId);
        if (StringUtils.isNotBlank(user.getAppOpenId())){
            userMap.setAppOpenId(user.getAppOpenId());
        }
        userService.updateFsUser(userMap);
    }

    private R generateTokenAndReturn(FsUser user) {
        String token = jwtUtils.generateToken(user.getUserId());
        redisCache.setCacheObject("userToken:" + user.getUserId(), token, 604800, TimeUnit.SECONDS);
        int isFirstLogin = userNewTaskService.performTaskOne(user.getUserId());
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("user", user);
        map.put("isFirst",isFirstLogin);
        return R.ok(map);
    }

    private R handleLoginType1(FsUserLoginParam param) {
        if (StringUtils.isEmpty(param.getPhone()) || StringUtils.isEmpty(param.getPassword())) {
            return R.error("账号或密码不能为空");
        }

        FsUser user = findUserByPhone(param.getPhone());

        // 校验用户是否存在及账号状态
        if (user == null) {
            return R.error("账号不存在，请先注册账号");
        } else if (user.getStatus() == 0) {
            return R.error("账号已停用");
        } else if (StringUtils.isEmpty(user.getPassword())) {
            return R.error("账号不存在，请先注册账号");
        }

        if (StringUtils.isNotEmpty(param.getJpushId())) {
            updateExistingUserJpushId(user, param.getJpushId());
        }

        if (!Md5Utils.hash(param.getPassword()).equals(user.getPassword())) {
            return R.error("密码不正确");
        }

        return generateTokenAndReturn(user);

    }

    private R handleLoginType3(FsUserLoginParam param) {
        if (StringUtils.isEmpty(param.getPhone())) {
            return R.error("获取手机号失败");
        }
        // 根据手机号查询用户
        FsUser user = findUserByPhone(param.getPhone());
        if (user == null) {
            createNewUser(param);
            return R.ok().put("isNew",true).put("phone",encryptPhone(param.getPhone()));
        } else {
            if (user.getUnionId()==null){
                if (user.getPhone().length()<=11){
                    FsUser fsUser = new FsUser();
                    fsUser.setUserId(user.getUserId());
                    fsUser.setPhone(encryptPhone(param.getPhone()));
                    userMapper.updateFsUser(fsUser);
                    logger.info("zyp \n【手机加密】：{}",encryptPhone(param.getPhone()));
                }
                return R.ok().put("isNew",true).put("phone",encryptPhone(param.getPhone()));
            }
            if (StringUtils.isNotEmpty(param.getJpushId())) {
                updateExistingUserJpushId(user, param.getJpushId());
            }
        }
        return generateTokenAndReturn(user);
    }

    private FsUser createNewUser(FsUserLoginParam param) {
        FsUser newUser = new FsUser();
        newUser.setLoginDevice(param.getLoginDevice() != null ? param.getLoginDevice() : null);
        newUser.setSource(param.getSource() != null ? param.getSource() : null );
        newUser.setNickName("匿名用户**");
        newUser.setPhone(param.getPhone());
        newUser.setCreateTime(new Date());
        newUser.setStatus(1);
        newUser.setAvatar("https://cos.his.cdwjyyh.com/fs/20240926/420728ee06e54575ba82665dedb4756b.png");
        if (StringUtils.isNotEmpty(param.getJpushId())) {
            newUser.setJpushId(param.getJpushId());
        }
        userService.insertFsUser(newUser);
        return newUser;
    }

    private FsUser findUserByPhone(String phone) {
        // 先根据加密手机号查询用户
        String jiami = (encryptPhone(phone));
        FsUser user = userMapper.selectFsUserByPhoneLimitOne(jiami);

        // 如果没有找到用户，再根据手机号查询
        if (user == null) {
            user = userMapper.selectFsUserByPhoneLimitOne(phone);

        }
        return user;
    }

    @PostMapping("/loginTest")
    public R loginTest(@RequestBody String userId) {
        FsUser user = userMapper.selectFsUserByUserId(Long.parseLong(userId));
        if (user!=null){
            String token = jwtUtils.generateToken(user.getUserId());
            redisCache.setCacheObject("userToken:" + user.getUserId(), token, 604800, TimeUnit.SECONDS);
            Map<String, Object> map = new HashMap<>();
            map.put("token", token);
            map.put("user", user);
            return R.ok(map);
        }
        return R.error("用户不存在！");
    }

    /**
     * 退出清除jpushId
     */
    @Login
    @GetMapping("/logout")
    public R logout() {
        String userId = getUserId();
        FsUser fsUser = new FsUser();
        fsUser.setUserId(Long.parseLong(userId));
        fsUser.setJpushId("");
        if (userMapper.updateFsUser(fsUser)>0) {
            return R.ok();
        } else {
            return R.error("用户不存在！");
        }
    }

    /**
     * 更新jpushId
     */
    @Login
    @GetMapping("/updatePushId")
    public R updatePushId(@Param("pushId") String pushId) {
        String userId = getUserId();
        FsUser fsUser = new FsUser();
        fsUser.setUserId(Long.parseLong(userId));
        fsUser.setJpushId(pushId);
        if (userMapper.updateFsUser(fsUser)>0) {
            return R.ok();
        } else {
            return R.error("用户不存在！");
        }
    }

    @PostMapping("/sendCode")
    public R sendCode(@RequestBody Map<String, String> body){
        String phone = body.get("phone");
        String encryptPhone = encryptPhone(phone);
        List<FsUser> user = userService.selectFsUserListByPhone(encryptPhone);
        if(CollectionUtil.isEmpty(user)){
            user = userService.selectFsUserListByPhone(encryptPhoneOldKey(phone));
            if (CollectionUtil.isEmpty(user)){
                user = userService.selectFsUserListByPhone(phone);
            }
        }
        if (CollectionUtil.isEmpty(user)){
            return R.error("此电话号码未绑定用户");
        }

        // 验证码 key（3分钟有效）
        String smsCodeKey = "sms:code:" + phone;
        // 冷却 key（60秒内不能重复发送）
        String smsCooldownKey = "sms:cooldown:" + phone;

        // 判断是否在 60 秒冷却期
        if (redisCache.getCacheObject(smsCooldownKey) != null) {
            return R.error("验证码已发送，请稍后再试");
        }

        // 生成新验证码
        String smsCode = VerifyCodeUtil.generateCode();

        // 发送短信
        smsService.sendCaptcha(phone, smsCode, "验证码");

        // 缓存验证码（3分钟有效）
        redisCache.setCacheObject(smsCodeKey, smsCode, 180, TimeUnit.SECONDS);
        // 设置冷却时间（60秒内不能再发）
        redisCache.setCacheObject(smsCooldownKey, "1", 60, TimeUnit.SECONDS);

        return R.ok("验证码已发送");
    }

    /**
     * 添加appId到用户的appId列表中（如果不存在）
     * @param currentAppIds 当前用户已有的appId列表（逗号分隔）
     * @param newAppId 新的appId
     * @return 更新后的appId列表
     */
    private String addAppIdIfNotExists(String currentAppIds, String newAppId) {
        // 如果新appId为空，返回原值
        if (StringUtils.isEmpty(newAppId)) {
            return currentAppIds == null ? "" : currentAppIds;
        }

        // 如果当前appId为空，直接返回新appId
        if (StringUtils.isEmpty(currentAppIds)) {
            return newAppId;
        }

        // 检查是否已存在
        String[] appIdArray = currentAppIds.split(",");
        for (String appId : appIdArray) {
            if (appId.trim().equals(newAppId.trim())) {
                // 已存在，不需要添加
                return currentAppIds;
            }
        }

        // 不存在，追加到末尾
        return currentAppIds + "," + newAppId;
    }
}
