package com.YuyeTech.TPlat.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.YuyeTech.TPlat.VO.EmailVO;
import com.YuyeTech.TPlat.dataobject.*;
import com.YuyeTech.TPlat.form.ClientForm;
import com.YuyeTech.TPlat.form.FeedbackForm;
import com.YuyeTech.TPlat.service.*;
import com.YuyeTech.TPlat.utils.*;
import com.alibaba.fastjson.JSONObject;
import com.YuyeTech.TPlat.VO.LoginVO;
import com.YuyeTech.TPlat.VO.ResultVO;
import com.YuyeTech.TPlat.VO.UserInfoVO;
import com.YuyeTech.TPlat.config.WxMaConfiguration;
import com.YuyeTech.TPlat.constant.CookieConstant;
import com.YuyeTech.TPlat.constant.RedisConstant;
import com.YuyeTech.TPlat.enums.ResultEnum;
import com.YuyeTech.TPlat.enums.UserEnum;
import com.YuyeTech.TPlat.enums.WxInfoEnum;
import com.YuyeTech.TPlat.exception.UserException;
import com.YuyeTech.TPlat.exception.WxInfoException;

import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 登录
 *
 * @author:slambb
 * @date:2019/12/4
 */
@RestController
@RequestMapping("/program")
@Slf4j
public class LoginController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MainInfoService mainInfoService;


    @Autowired
    private WxInfoService wxInfoService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private AliyunSMSUtil aliyunSMSUtil;

    @Autowired
    private AppleInfoService appleInfoService;

    @Autowired
    private ClientInfoService clientInfoService;

    @Autowired
    private VersionCodeService versionCodeService;

    @Value("${spring.mail.username}")
    private String mailUsername;

    @Autowired
    private JavaMailSender mailSender;
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;




    @GetMapping("/getSessionToken")
    public ResultVO getSessionToken(@RequestParam("code") String code) {

        log.info("进入getSessionToken 方法。");
        log.info("code={}", code);

        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx463e58507db8f1ef&secret=ba04f48301d083e961d6f84cc696aeb2&code=" + code + "&grant_type=authorization_code";

        RestTemplate restTemplate = new RestTemplate();
        String response = restTemplate.getForObject(url, String.class);
        log.info("response={}", response);
        ResultVO resultVO = new ResultVO();
        resultVO.setCode(0);
        resultVO.setMsg("成功");
        resultVO.setData(response);

        return resultVO;

    }

    /**
     * android 端登录，微信登录
     * 只要带login，都不用权鉴
     *
     * @param openid
     * @param unionid
     * @param response
     * @param request
     * @return
     */
    @GetMapping("/client_wx_login")
    public ResultVO androidWxLogin(@RequestParam("openid") String openid,
                                   @RequestParam("unionid") String unionid,
                                   HttpServletResponse response,
                                   HttpServletRequest request) {
        //检查redis 的token 是否存在，存在则删除
        String headToken = request.getHeader("token");
        if (StringUtils.isNotBlank(headToken)) {
            Boolean bSuccess = redisTemplate.delete(String.format(RedisConstant.TOKEN_PREFIX, headToken));
            if (!bSuccess) {
                //删除不成功，redis不存在，是非法token
                log.info("redis 没有对应的token");
            }
        }
        try {
            String token = UUID.randomUUID().toString();
            Integer expire = RedisConstant.EXPIRE;//过期时间
            Map<String, String> tokenMap = new HashMap<>();

            //1.openid 和 wxInfo数据库的对比,没有用户的话，添加新增用户
            WxInfo wxInfo = wxInfoService.findWxInfoByOpenid(openid);
            //2. wxInfo 没有数据，添加新数据
            MainInfo mainInfo = new MainInfo();
            if (wxInfo == null) {
                //先main_info主表添加信息
                mainInfo = createMainInfo();
                mainInfoService.addMainInfo(mainInfo);
                //微信表添加信息 wx_info
                wxInfo = new WxInfo();
                wxInfo.setUserId(mainInfo.getUserId());
                wxInfo.setOpenid(openid);
                wxInfo.setUnionid(unionid);
                wxInfoService.addWxInfo(wxInfo);
            } else {
                mainInfo = mainInfoService.findMainInfoById(wxInfo.getUserId());
            }

            //拿到用户userid
            tokenMap.put("userId", mainInfo.getUserId());
            tokenMap.put("openid", openid);
            tokenMap.put("unionid", unionid);

            //2.设置token 到redis
            redisTemplate.opsForHash().putAll(String.format(RedisConstant.TOKEN_PREFIX, token), tokenMap);
            redisTemplate.expire(String.format(RedisConstant.TOKEN_PREFIX, token), expire, TimeUnit.SECONDS);
            //3.设置token到cookie
            CookieUtil.set(response, CookieConstant.TOKEN, token, expire);
            //TODO 可以增加自己的逻辑，关联业务相关数据
            //用userInfo 来判断是否存在userInfo 表中，
            LoginVO loginVO = new LoginVO();
            loginVO.setToken(token);
            loginVO.setNewUser(bUserInfoByUserId(mainInfo.getUserId()));
            return ResultVOUtil.success(loginVO);
        } catch (UserException e) {
            log.error(e.getMessage(), e);
            return ResultVOUtil.error(e.getCode(), e.toString());
        }

    }

    //调用创建一个mainInfo
    public MainInfo createMainInfo() {
        String _id = KeyUtil.genUniqueKey();
        MainInfo mainInfo = new MainInfo();
        mainInfo.setUserId(_id);
        mainInfo.setUsername("u_" + _id);
        mainInfo.setPassword("p_" + _id);
        return mainInfo;
    }

    //查看是否存在 UserInfo里面；
    public Boolean bUserInfoByUserId(String userId) {
        UserInfo saveUserInfo = userInfoService.findUserInfoById(userId, true);
        Boolean bNewUser = saveUserInfo == null ? true : false;
        return bNewUser;
    }

    /**
     * 小程序端登录
     *
     * @param appid
     * @param code
     * @param platFrom
     * @param response
     * @param request
     * @return
     */
    @GetMapping("/client_login")
    public ResultVO client_login(@RequestParam("appid") String appid,
                                 @RequestParam("code") String code,
                                 @RequestParam("platfrom") String platFrom,
                                 HttpServletResponse response,
                                 HttpServletRequest request) {
        //检查redis 的token 是否存在，存在则删除
        String headToken = request.getHeader("token");
        if (StringUtils.isNotBlank(headToken)) {
            Boolean bSuccess = redisTemplate.delete(String.format(RedisConstant.TOKEN_PREFIX, headToken));
            if (!bSuccess) {
                //删除不成功，redis不存在，是非法token
//                throw new WxInfoException(ResultEnum.TOKEN_IS_ILLEGAL.getCode(), ResultEnum.TOKEN_IS_ILLEGAL.getMessage());
                log.info("redis 没有对应的token");
            }
        }

        //1.配置
        //2.调用方法
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);

        try {
            //token
            String token = UUID.randomUUID().toString();
            Integer expire = RedisConstant.EXPIRE;//过期时间

            Map<String, String> tokenMap = new HashMap<>();
            if (StringUtils.equals(platFrom, "weixin")) {
                WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
                //1.openid 和数据库的对比,没有用户的话，添加新增用户
                WxInfo wxInfo = wxInfoService.findWxInfoByOpenid(session.getOpenid());

                if (wxInfo == null) {
                    //先main_info主表添加信息
                    MainInfo mainInfo = createMainInfo();
                    mainInfoService.addMainInfo(mainInfo);
                    //微信表添加信息 wx_info
                    wxInfo = new WxInfo();
                    wxInfo.setUserId(mainInfo.getUserId());
                    wxInfo.setOpenid(session.getOpenid());
                    wxInfoService.addWxInfo(wxInfo);
                }

                //拿到微信对应的用户userid
                tokenMap.put("userId", wxInfo.getUserId());
                tokenMap.put("openid", session.getOpenid());
                tokenMap.put("sessionKey", session.getSessionKey());
                tokenMap.put("unionid", session.getUnionid());
            }
            //2.设置token 到redis
            // redisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_PREFIX,token),session.getOpenid()+session.getSessionKey(),expire, TimeUnit.SECONDS);
            redisTemplate.opsForHash().putAll(String.format(RedisConstant.TOKEN_PREFIX, token), tokenMap);
            redisTemplate.expire(String.format(RedisConstant.TOKEN_PREFIX, token), expire, TimeUnit.SECONDS);
            //3.设置token到cookie
            CookieUtil.set(response, CookieConstant.TOKEN, token, expire);
            //TODO 可以增加自己的逻辑，关联业务相关数据
            LoginVO loginVO = new LoginVO();
            loginVO.setToken(token);
            return ResultVOUtil.success(loginVO);
        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
            return ResultVOUtil.error(500, e.toString());
        }
    }

    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @GetMapping("/wx_getUserInfo")
    public ResultVO wxGetUserInfo(
            @RequestParam("appid") String appid,
            @RequestParam("signature") String signature,
            @RequestParam("rawData") String rawData,
            @RequestParam("encryptedData") String encryptedData,
            @RequestParam("iv") String iv,
            @RequestParam("userId") String userId,
            HttpServletRequest request) {
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
//        String cookie= request.getHeader("cookies");
        //获取到请求后，查询cookie
//        Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
        String token = request.getHeader("token");
        Object sessionKey = redisTemplate.opsForHash().get(String.format(RedisConstant.TOKEN_PREFIX, token), "sessionKey");
        // 用户信息校验
        if (!wxService.getUserService().checkUserInfo(sessionKey.toString(), rawData, signature)) {
//            return "user check failed";
            throw new WxInfoException(WxInfoEnum.USER_WX_ENCRYPTED_DATA_ERROR);
        }
        // 解密用户信息
        WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey.toString(), encryptedData, iv);

        //解密用户信息时候，如果是新用户，则把用户信息存入数据库
        UserInfo saveUserInfo = userInfoService.findUserInfoById(userId, true);
        if (saveUserInfo == null) {
            saveUserInfo = new UserInfo();
            saveUserInfo.setUserId(request.getParameterValues("userId")[0]);
            saveUserInfo.setUsername(userInfo.getNickName());
            saveUserInfo.setGender(userInfo.getGender());
            saveUserInfo.setBirthday(new Date());
            saveUserInfo.setSignature("");
            saveUserInfo.setAvatarUrl(userInfo.getAvatarUrl());
            saveUserInfo.setHeight(0.0);
            saveUserInfo.setWeight(0.0);
            saveUserInfo.setRegisterTime(new Date());
            saveUserInfo.setStatus(1);//1为新注册
            userInfoService.addUserInfo(saveUserInfo);
        }


//        return JsonUtils.toJson(userInfo);
        //vo 返回给前端的字段筛选
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(saveUserInfo, userInfoVO);
        return ResultVOUtil.success(userInfoVO);
    }

    /**
     * 获取验证码
     *
     * @param phoneNumber
     * @return
     */
    @GetMapping("/getCode")
    public ResultVO getCode(@RequestParam(value = "phoneNumber") String phoneNumber) {
        Integer expire = RedisConstant.CODE_EXPIRE;//过期时间
        String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
        if (phoneNumber != null) {
            aliyunSMSUtil.sendSms(phoneNumber, code);
            //成功后保存code到redis
            redisTemplate.opsForValue().set(String.format(RedisConstant.SMS_PREFIX, phoneNumber), code, expire, TimeUnit.SECONDS);
            log.info("getCode:" + code);
            return ResultVOUtil.success();
        } else {
            return ResultVOUtil.error(200, "获取code失败");
        }
    }

    /**
     * 2021-09-18
     * 在手机号或者邮件中获取验证码。通用
     *
     * @param account
     * @param type 0 默认手机，1默认邮件
     * @return
     */
    @GetMapping("/getCodeAccordingType")
    public ResultVO getCodeAccordingType(@RequestParam(value = "account") String account,
                                         @RequestParam(value = "type") Integer type) {
        Integer expire = RedisConstant.CODE_EXPIRE;//过期时间
        String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
        if (account != null) {

            if(type.equals(0)){
                //发送验证码给 手机
                aliyunSMSUtil.sendSms(account, code);
            }else if(type.equals(1)){
                //发送验证码给 邮件
                //创建简单邮件消息
//                SimpleMailMessage message = new SimpleMailMessage();

                //邮件内容
//                message.setText("哔蹦平台登录的验证码："+code+"，请勿泄露给其他人！");
                //freemarker
                try {
                    MimeMessage message = mailSender.createMimeMessage();
                    MimeMessageHelper helper = new MimeMessageHelper(message);
                    //谁发的
                    helper.setFrom(mailUsername);
                    //谁要接收
                    helper.setTo(account);
                    //邮件标题
                    helper.setSubject("哔蹦平台验证码");
                    //freemarker
                    Template template = freeMarkerConfigurer.getConfiguration().getTemplate("/mail/sendSMS.ftl");
                    Map<String, String> emailMap = new HashMap<>();
                    emailMap.put("emailCode",code);
                    String s = FreeMarkerTemplateUtils.processTemplateIntoString(template, emailMap);
                    helper.setText(s,true);
                    mailSender.send(message);

                } catch (MailException e) {
                    return ResultVOUtil.error(200, "发送普通邮件方失败！");
                }catch (MessagingException e) {
                    return ResultVOUtil.error(200, "发送普通邮件方失败！");
                } catch (IOException e) {
                    return ResultVOUtil.error(200, "发送普通邮件方失败！");
                } catch (TemplateException e) {
                    return ResultVOUtil.error(200, "发送普通邮件方失败！");
                }


            }
            //成功后保存code到redis
            redisTemplate.opsForValue().set(String.format(RedisConstant.SMS_PREFIX, account), code, expire, TimeUnit.SECONDS);
            log.info("getCode:" + code);
            Map map = new HashMap();
            map.put("receiver",account);
            map.put("tip","发送验证码成功");
            map.put("type",type);
            return ResultVOUtil.success(map);
        } else {
            return ResultVOUtil.error(200, "获取code失败");
        }
    }

    /**
     * 验证码绑定号码
     * 2.4.12 版本后弃用
     * @param phoneNumber
     * @param code
     * @return
     */
    @GetMapping("/SMS_bind_phone")
    @Deprecated
    public ResultVO userBindPhoneNumber(@RequestParam("phoneNumber") String phoneNumber,
                                        @RequestParam("code") String code,
                                        @RequestParam("userId") String userId) {

        String codeValue = redisTemplate.opsForValue().get(String.format(RedisConstant.SMS_PREFIX, phoneNumber));
        if (!StringUtils.equals(codeValue, code)) {
            return ResultVOUtil.error(UserEnum.USER_CODE_ERROR.getCode(), UserEnum.USER_CODE_ERROR.getMessage());
        }
        log.info("codeValue:" + codeValue);

        try {

            MainInfo phoneMainInfo = mainInfoService.findMainInfoByPhoneNumber(phoneNumber);
            if (phoneMainInfo != null) {
                //如果存在，此手机号提示已注册
                return ResultVOUtil.error(UserEnum.USER_HAS_REGISTER_PHONE.getCode(), UserEnum.USER_HAS_REGISTER_PHONE.getMessage());
            }

            MainInfo mainInfo = mainInfoService.findMainInfoById(userId);
            //TODO 验证码登录流程
            //如果不存在用户
            if (mainInfo == null) {
                return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
            }

            mainInfo.setTelephoneNumber(phoneNumber);
            mainInfoService.addMainInfo(mainInfo);
            //TODO 写入成功后，删除redis里面保存的code
            Boolean bSuccess = redisTemplate.delete(String.format(RedisConstant.SMS_PREFIX, phoneNumber));
            if (!bSuccess) {
                //删除不成功，redis不存在
                log.info("redis 没有对应的token");
            }
            return ResultVOUtil.success();

        } catch (UserException e) {
            return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
        }

    }

    /**
     * 验证码绑定号码或者邮箱
     *
     * @param account
     * @param code
     * @return
     */
    @GetMapping("/SMS_bind_account")
    public ResultVO userBindAccount(@RequestParam("account") String account,
                                        @RequestParam("code") String code,
                                        @RequestParam("type") Integer type,
                                        @RequestParam("userId") String userId) {

        String codeValue = redisTemplate.opsForValue().get(String.format(RedisConstant.SMS_PREFIX, account));
        if (!StringUtils.equals(codeValue, code)) {
            return ResultVOUtil.error(UserEnum.USER_CODE_ERROR.getCode(), UserEnum.USER_CODE_ERROR.getMessage());
        }
        log.info("codeValue:" + codeValue);

        try {
            MainInfo mainInfo = null;
            if(type.equals(0)){
                mainInfo = mainInfoService.findMainInfoByPhoneNumber(account);
                if (mainInfo != null) {
                    //如果存在，此手机号提示已注册
                    return ResultVOUtil.error(UserEnum.USER_HAS_REGISTER_PHONE.getCode(), UserEnum.USER_HAS_REGISTER_PHONE.getMessage());
                }
            }else if(type.equals(1)){
                mainInfo = mainInfoService.findMainInfoByEmail(account);
                if (mainInfo != null) {
                    //如果存在，此手机号提示已注册
                    return ResultVOUtil.error(UserEnum.USER_HAS_REGISTER_MAILBOX.getCode(), UserEnum.USER_HAS_REGISTER_MAILBOX.getMessage());
                }
            }

            mainInfo = mainInfoService.findMainInfoById(userId);
            //TODO 验证码登录流程
            //如果不存在用户
            if (mainInfo == null) {
                return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
            }
            if(type.equals(0)){
                mainInfo.setTelephoneNumber(account);
            }else if(type.equals(1)){
                mainInfo.setEmail(account);
            }
            mainInfoService.addMainInfo(mainInfo);
            //TODO 写入成功后，删除redis里面保存的code
            Boolean bSuccess = redisTemplate.delete(String.format(RedisConstant.SMS_PREFIX, account));
            if (!bSuccess) {
                //删除不成功，redis不存在
                log.info("redis 没有对应的token");
            }
            return ResultVOUtil.success();

        } catch (UserException e) {
            return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
        }

    }


    @GetMapping("/delete_phone")
    public ResultVO userDeletePhoneNumber(@RequestParam("userId") String userId) {
        try {
            MainInfo mainInfo = mainInfoService.findMainInfoById(userId);
            //TODO 验证码登录流程
            //如果不存在用户
            if (mainInfo == null) {
                return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
            }
            mainInfo.setTelephoneNumber(null);
            mainInfoService.addMainInfo(mainInfo);
            return ResultVOUtil.success();
        } catch (UserException e) {
            return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
        }

    }


    @GetMapping("/bind_wx_info")
    public ResultVO userBindWXInfo(@RequestParam("openid") String openid,
                                   @RequestParam("unionid") String unionid,
                                   @RequestParam("userId") String userId) {
        try {
            MainInfo mainInfo = mainInfoService.findMainInfoById(userId);
            //TODO 验证码登录流程
            //如果不存在用户
            if (mainInfo == null) {
                return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
            }

            //需要检查微信是否被绑定过,如果wxInfo 表存在openid 对应的用户，提示微信已绑定，用户需绑定其他微信账号
            WxInfo wxInfo = wxInfoService.findWxInfoByOpenid(openid);
            if (wxInfo == null) {
                wxInfo = new WxInfo();
                wxInfo.setUnionid(unionid);
                wxInfo.setOpenid(openid);
                wxInfo.setUserId(userId);
                wxInfoService.addWxInfo(wxInfo);
            } else {
                //提示用户微信已被使用
                return ResultVOUtil.error(UserEnum.USER_HAS_REGISTER_WX.getCode(), UserEnum.USER_HAS_REGISTER_WX.getMessage());
            }

            return ResultVOUtil.success();
        } catch (UserException e) {
            return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
        }

    }

    /**
     * 验证码登录
     * 2.4.15 版本后弃用
     * @param phoneNumber
     * @param code
     * @return
     */
    @GetMapping("/SMS_login")
    @Deprecated
    public ResultVO userRegistrationAndSMSLogin(String phoneNumber, String code) {
        String codeValue = redisTemplate.opsForValue().get(String.format(RedisConstant.SMS_PREFIX, phoneNumber));
        if (!StringUtils.equals(codeValue, code)) {
            log.warn("【code校验】Redis 中查找不到验证码 {},==,{}", codeValue, code);
            return ResultVOUtil.error(UserEnum.USER_CODE_ERROR.getCode(), UserEnum.USER_CODE_ERROR.getMessage());
        }
        log.info("codeValue:" + codeValue);
        //token
        String token = UUID.randomUUID().toString();
        Integer expire = RedisConstant.EXPIRE;//过期时间
        Map<String, String> tokenMap = new HashMap<>();

        try {
            MainInfo mainInfo = mainInfoService.findMainInfoByPhoneNumber(phoneNumber);
            //TODO 验证码登录流程
            //如果不存在用户
            if (mainInfo == null) {
                //先main_info主表添加信息
                mainInfo = createMainInfo();
                mainInfo.setTelephoneNumber(phoneNumber);
                mainInfoService.addMainInfo(mainInfo);
            }
            //TODO 写入成功后，删除redis里面保存的code
            Boolean bSuccess = redisTemplate.delete(String.format(RedisConstant.SMS_PREFIX, phoneNumber));
            if (!bSuccess) {
                //删除不成功，redis不存在
                log.info("redis 没有对应的token");
            }

            tokenMap.put("userId", mainInfo.getUserId());

            redisTemplate.opsForHash().putAll(String.format(RedisConstant.TOKEN_PREFIX, token), tokenMap);
            redisTemplate.expire(String.format(RedisConstant.TOKEN_PREFIX, token), expire, TimeUnit.SECONDS);

            //返回一个token
            LoginVO loginVO = new LoginVO();
            loginVO.setToken(token);
            loginVO.setNewUser(bUserInfoByUserId(mainInfo.getUserId()));
            return ResultVOUtil.success(loginVO);

        } catch (UserException e) {

            log.error(e.getMessage(), e);
            return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
        }

    }

    @GetMapping("/SMS_login_from_type")
    public ResultVO userRegistrationAndSMSLogin(String account, String code, Integer type) {
        String codeValue = redisTemplate.opsForValue().get(String.format(RedisConstant.SMS_PREFIX, account));
        if (!StringUtils.equals(codeValue, code)) {
            log.warn("【code校验】Redis 中查找不到验证码 {},==,{}", codeValue, code);
            return ResultVOUtil.error(UserEnum.USER_CODE_ERROR.getCode(), UserEnum.USER_CODE_ERROR.getMessage());
        }
        log.info("codeValue:" + codeValue);
        //token
        String token = UUID.randomUUID().toString();
        Integer expire = RedisConstant.EXPIRE;//过期时间
        Map<String, String> tokenMap = new HashMap<>();

        try {
            MainInfo mainInfo = null;
            if(type.equals(0)){
                mainInfo = mainInfoService.findMainInfoByPhoneNumber(account);
            }else if(type.equals(1)){
                mainInfo = mainInfoService.findMainInfoByEmail(account);
            }
            //TODO 验证码登录流程
            //如果不存在用户
            if (mainInfo == null) {
                //先main_info主表添加信息
                mainInfo = createMainInfo();
                if(type.equals(0)){
                    mainInfo.setTelephoneNumber(account);
                }else if(type.equals(1)){
                    mainInfo.setEmail(account);
                }
                mainInfoService.addMainInfo(mainInfo);
            }
            //TODO 写入成功后，删除redis里面保存的code
            Boolean bSuccess = redisTemplate.delete(String.format(RedisConstant.SMS_PREFIX, account));
            if (!bSuccess) {
                //删除不成功，redis不存在
                log.info("redis 没有对应的token");
            }

            tokenMap.put("userId", mainInfo.getUserId());

            redisTemplate.opsForHash().putAll(String.format(RedisConstant.TOKEN_PREFIX, token), tokenMap);
            redisTemplate.expire(String.format(RedisConstant.TOKEN_PREFIX, token), expire, TimeUnit.SECONDS);

            //返回一个token
            LoginVO loginVO = new LoginVO();
            loginVO.setToken(token);
            loginVO.setNewUser(bUserInfoByUserId(mainInfo.getUserId()));
            return ResultVOUtil.success(loginVO);

        } catch (UserException e) {

            log.error(e.getMessage(), e);
            return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
        }

    }

    /**
     * 密码登录
     * 2.4.10 版本后弃用
     * @param phoneNumber
     * @param password
     * @return
     */
    @GetMapping("/password_login")
    @Deprecated
    public ResultVO userPasswordLogin(String phoneNumber, String password) {
        try {
            MainInfo mainInfo = mainInfoService.findMainInfoByPhoneNumberAndPassword(phoneNumber, password);

            //TODO 密码登录流程判断
//            if(!StringUtils.equals(mainInfo.getTelephoneNumber(),phoneNumber)){
//                return ResultVOUtil.error(UserEnum.USER_NOT_PHONE_NUMBER.getCode(),UserEnum.USER_NOT_PHONE_NUMBER.getMessage());
//            }
//            if(!StringUtils.equals(mainInfo.getPassword(),password)){
//                return ResultVOUtil.error(UserEnum.USER_PASSWORD_ERROR.getCode(),UserEnum.USER_PASSWORD_ERROR.getMessage());
//            }
            if (mainInfo == null) {
                return ResultVOUtil.error(UserEnum.USER_PASSWORD_ERROR.getCode(), UserEnum.USER_PASSWORD_ERROR.getMessage());
            }
            //token
            String token = UUID.randomUUID().toString();
            Integer expire = RedisConstant.EXPIRE;//过期时间
            Map<String, String> tokenMap = new HashMap<>();

            //TODO 登录成功，返回对应的字段
            tokenMap.put("userId", mainInfo.getUserId());
            redisTemplate.opsForHash().putAll(String.format(RedisConstant.TOKEN_PREFIX, token), tokenMap);
            redisTemplate.expire(String.format(RedisConstant.TOKEN_PREFIX, token), expire, TimeUnit.SECONDS);

            //返回一个token
            LoginVO loginVO = new LoginVO();
            loginVO.setToken(token);
            loginVO.setNewUser(bUserInfoByUserId(mainInfo.getUserId()));
            return ResultVOUtil.success(loginVO);
        } catch (UserException e) {

            log.error(e.getMessage(), e);
            return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
        }


    }

    /**
     * 密码登录
     *
     * @param account
     * @param password
     * @return
     */
    @GetMapping("/password_login_type")
    public ResultVO userPasswordLoginOnTheType(String account, String password,Integer type) {
        try {
            MainInfo mainInfo = null;
            if(type.equals(0)){
                mainInfo = mainInfoService.findMainInfoByPhoneNumberAndPassword(account, password);
            }else if(type.equals(1)){
                mainInfo = mainInfoService.findMainInfoByEmailAndPassword(account, password);
            }

            if (mainInfo == null) {
                return ResultVOUtil.error(UserEnum.USER_PASSWORD_ERROR.getCode(), UserEnum.USER_PASSWORD_ERROR.getMessage());
            }
            //token
            String token = UUID.randomUUID().toString();
            Integer expire = RedisConstant.EXPIRE;//过期时间
            Map<String, String> tokenMap = new HashMap<>();

            //TODO 登录成功，返回对应的字段
            tokenMap.put("userId", mainInfo.getUserId());
            redisTemplate.opsForHash().putAll(String.format(RedisConstant.TOKEN_PREFIX, token), tokenMap);
            redisTemplate.expire(String.format(RedisConstant.TOKEN_PREFIX, token), expire, TimeUnit.SECONDS);

            //返回一个token
            LoginVO loginVO = new LoginVO();
            loginVO.setToken(token);
            loginVO.setNewUser(bUserInfoByUserId(mainInfo.getUserId()));
            return ResultVOUtil.success(loginVO);
        } catch (UserException e) {

            log.error(e.getMessage(), e);
            return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
        }


    }

    /**
     * 用来验证一下信息
     *
     * @return
     */
    @GetMapping("/Verification_Info")
    public ResultVO VerificationInfo(@RequestParam(value = "token", required = false) String token,
                                     @RequestParam("userId") String userId) {

        //如果有token，刷新信息
//        if (null == token || token.isEmpty())
//        {
//            Integer expire = RedisConstant.EXPIRE;//过期时间
//            redisTemplate.expire(String.format(RedisConstant.TOKEN_PREFIX, token), expire, TimeUnit.SECONDS);
//        }
        LoginVO loginVO = new LoginVO();
        loginVO.setNewUser(bUserInfoByUserId(userId));
        return ResultVOUtil.success(loginVO);
    }

    /**
     * 删除token
     *
     * @param request
     * @return
     */
    @GetMapping("/delete_token")
    public ResultVO delectToken(HttpServletRequest request) {

        String headToken = request.getHeader("token");
        if (StringUtils.isNotBlank(headToken)) {
            Boolean bSuccess = redisTemplate.delete(String.format(RedisConstant.TOKEN_PREFIX, headToken));
            if (!bSuccess) {
                //删除不成功，redis不存在，是非法token
                log.info("redis 没有对应的token");
                return ResultVOUtil.error(ResultEnum.TOKEN_IS_ILLEGAL.getCode(), ResultEnum.TOKEN_IS_ILLEGAL.getMessage());
            }
        }
        return ResultVOUtil.success();
    }




    @GetMapping("/client_apple_login")
    public ResultVO appleLogin(@RequestParam("identityToken") String identityToken,
                                   HttpServletResponse response,
                                   HttpServletRequest request) {


        //检查redis 的token 是否存在，存在则删除
        String headToken = request.getHeader("token");
        if (StringUtils.isNotBlank(headToken)) {
            Boolean bSuccess = redisTemplate.delete(String.format(RedisConstant.TOKEN_PREFIX, headToken));
            if (!bSuccess) {
                //删除不成功，redis不存在，是非法token
                log.info("redis 没有对应的token");
            }
        }

        //todo 处理identityToken,判断是否是非法，暂时默认全部合法


        try {
            //验证identityToken
            if(!AppleUtil.verify(identityToken)){
                log.info("identityToken：{}",ResultEnum.APPLE_LOGIN_VALIDATION_FAIL.getMessage());
                return ResultVOUtil.error(ResultEnum.APPLE_LOGIN_VALIDATION_FAIL.getCode(),
                    ResultEnum.APPLE_LOGIN_VALIDATION_FAIL.getMessage());
            }
            //对identityToken解码
            JSONObject json = AppleUtil.parserIdentityToken(identityToken);
            if(json == null){
                log.info("identityToken：{}",ResultEnum.APPLE_LOGIN_TOKEN_FAIL.getMessage());
                return ResultVOUtil.error(ResultEnum.APPLE_LOGIN_TOKEN_FAIL.getCode(),
                        ResultEnum.APPLE_LOGIN_TOKEN_FAIL.getMessage());
            }

            log.info("验证通过的json信息：{}",json);

            String token = UUID.randomUUID().toString();
            Integer expire = RedisConstant.EXPIRE;//过期时间
            Map<String, String> tokenMap = new HashMap<>();

            //1.userID 和 appleInfo数据库的appleId对比,没有用户的话，添加新增用户
            AppleInfo appleInfo = appleInfoService.findByAppleId(json.getString("sub"));
            //2. appleInfo 没有数据，添加新数据
            MainInfo mainInfo = new MainInfo();
            if (appleInfo == null) {
                //先main_info主表添加信息
                mainInfo = createMainInfo();
                mainInfoService.addMainInfo(mainInfo);
                //微信表添加信息 wx_info
                appleInfo = new AppleInfo();
                appleInfo.setUserId(mainInfo.getUserId());
                appleInfo.setAppleId(json.getString("sub"));
                appleInfoService.addAppleInfo(appleInfo);
            } else {
                mainInfo = mainInfoService.findMainInfoById(appleInfo.getUserId());
            }

            //拿到用户userid
            tokenMap.put("userId", mainInfo.getUserId());
            tokenMap.put("appleId", appleInfo.getAppleId());

            //2.设置token 到redis
            redisTemplate.opsForHash().putAll(String.format(RedisConstant.TOKEN_PREFIX, token), tokenMap);
            redisTemplate.expire(String.format(RedisConstant.TOKEN_PREFIX, token), expire, TimeUnit.SECONDS);
            //3.设置token到cookie
            CookieUtil.set(response, CookieConstant.TOKEN, token, expire);
            //TODO 可以增加自己的逻辑，关联业务相关数据
            //用userInfo 来判断是否存在userInfo 表中，
            LoginVO loginVO = new LoginVO();
            loginVO.setToken(token);
            loginVO.setNewUser(bUserInfoByUserId(mainInfo.getUserId()));
            return ResultVOUtil.success(loginVO);
        } catch (UserException e) {
            log.error(e.getMessage(), e);
            return ResultVOUtil.error(e.getCode(), e.toString());
        } catch (Exception e){
            log.error("app wxLogin error:" + e.getMessage(),e);
            return ResultVOUtil.error(500, "apple login 系统错误");
        }

    }

    /**
     * 更新用户使用的客户端信息
     * @param clientForm
     * @return
     */
    @PostMapping("/add_client_info")
    public ResultVO addClientInfo(
            @Valid ClientForm clientForm) {


        ClientInfo clientInfo = clientInfoService.findClientInfoByUserId(clientForm.getUserId());
        if(clientInfo == null){
            clientInfo = new ClientInfo();
        }
        BeanUtils.copyProperties(clientForm, clientInfo, PropertyUtil.getNullPropertyNames(clientForm));
//        log.info("==={}",clientInfo);
        clientInfo = clientInfoService.AddClientInfo(clientInfo);
        return ResultVOUtil.success(clientInfo);
    }



    @GetMapping("/get_version_code_state")
    public ResultVO getVersionCodeState(@RequestParam("code") String code,
                                        @RequestParam(value = "platform", required = false) Integer platform ) {
        try {
            VersionCode versionCode = versionCodeService.findByCode(code);

            if(versionCode ==  null){
                return ResultVOUtil.error(ResultEnum.VERSION_CODE_NULL.getCode(), ResultEnum.VERSION_CODE_NULL.getMessage());
            }

            HashMap map = new HashMap();

            //platform 0:android 1:ios 2:all
            //getLimitPlatform 0:全都限制，1:限制android，2:限制ios,3:都不限制
            if(versionCode.getLimitPlatform().equals(0)
                    ||(platform.equals(0) && versionCode.getLimitPlatform().equals(1))  // android
                    ||(platform.equals(1) && versionCode.getLimitPlatform().equals(2))) // ios
            {
                map.put("showGame",false);
                map.put("showVideo",false);
            }else{
                map.put("showGame",versionCode.getIsShowGame().equals(1));
                map.put("showVideo",versionCode.getIsShowVideo().equals(1));
            }
            map.put("versionCode",versionCode.getCode());
            map.put("title",versionCode.getTitle());

            return ResultVOUtil.success(map);
        } catch (UserException e) {
            return ResultVOUtil.error(ResultEnum.VERSION_CODE_ERROR.getCode(), ResultEnum.VERSION_CODE_ERROR.getMessage());
        }

    }


    /**
     * 根据手机号或者邮箱获取验证码
     * 用验证码修改密码
     *
     * @param account
     * @param code
     * @return
     */
    @GetMapping("/SMS_modify_password")
    public ResultVO userModifyPassword(@RequestParam("account") String account,
                                    @RequestParam("code") String code,
                                    @RequestParam("type") Integer type,
                                    @RequestParam("password") String password,
                                    @RequestParam("userId") String userId) {

        String codeValue = redisTemplate.opsForValue().get(String.format(RedisConstant.SMS_PREFIX, account));
        if (!StringUtils.equals(codeValue, code)) {
            return ResultVOUtil.error(UserEnum.USER_CODE_ERROR.getCode(), UserEnum.USER_CODE_ERROR.getMessage());
        }
        log.info("userModifyPassword codeValue:" + codeValue);
        try {
            MainInfo mainInfo = null;
            if(type.equals(0)){
                mainInfo = mainInfoService.findMainInfoByPhoneNumber(account);
            }else if(type.equals(1)){
                mainInfo = mainInfoService.findMainInfoByEmail(account);
            }
            //如果不存在用户
            if (mainInfo == null) {
                return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
            }
            //设置密码
            mainInfo.setPassword(password);
            mainInfoService.addMainInfo(mainInfo);
            //TODO 写入成功后，删除redis里面保存的code
            Boolean bSuccess = redisTemplate.delete(String.format(RedisConstant.SMS_PREFIX, account));
            if (!bSuccess) {
                //删除不成功，redis不存在
                log.info("redis 没有对应的token");
            }
            return ResultVOUtil.success();

        } catch (UserException e) {
            return ResultVOUtil.error(UserEnum.USER_REGISTER_ERROR.getCode(), UserEnum.USER_REGISTER_ERROR.getMessage());
        }

    }

    /**
     * 根据手机号或者邮箱，加旧密码，修改成新密码
     *
     */
    @GetMapping("/modify_password_from_account")
    public ResultVO userModifyPasswordFromAccount(@RequestParam("account") String account,
                                       @RequestParam("type") Integer type,
                                       @RequestParam("oldPassword") String oldPassword,
                                       @RequestParam("newPassword") String newPassword,
                                       @RequestParam("userId") String userId) {

        try {
            MainInfo mainInfo = null;
            if(type.equals(0)){
                mainInfo = mainInfoService.findMainInfoByPhoneNumber(account);
            }else if(type.equals(1)){
                mainInfo = mainInfoService.findMainInfoByEmail(account);
            }
            //如果不存在用户
            if (mainInfo == null) {
                return ResultVOUtil.error(UserEnum.USER_MODIFY_ACCOUNT_ERROR.getCode(), UserEnum.USER_MODIFY_ACCOUNT_ERROR.getMessage());
            }
            if(!mainInfo.getPassword().equals(oldPassword))
            {
                //如果旧密码不对，提示
                return ResultVOUtil.error(UserEnum.USER_OLD_PASSWORD_ERROR.getCode(), UserEnum.USER_OLD_PASSWORD_ERROR.getMessage());
            }
            //设置密码
            mainInfo.setPassword(newPassword);
            mainInfoService.addMainInfo(mainInfo);
            return ResultVOUtil.success();
        } catch (UserException e) {
            return ResultVOUtil.error(UserEnum.USER_MODIFY_ERROR.getCode(), UserEnum.USER_MODIFY_ERROR.getMessage());
        }

    }
}
