package com.slodon.b2b2c.controller.member.front;

import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSONObject;
import com.slodon.b2b2c.business.pojo.Cart;
import com.slodon.b2b2c.core.config.DomainUrlUtil;
import com.slodon.b2b2c.core.constant.MemberConst;
import com.slodon.b2b2c.core.constant.ResponseConst;
import com.slodon.b2b2c.core.controller.BaseController;
import com.slodon.b2b2c.core.exception.MallException;
import com.slodon.b2b2c.core.response.JsonResult;
import com.slodon.b2b2c.core.response.SldResponse;
import com.slodon.b2b2c.core.uid.GoodsIdGenerator;
import com.slodon.b2b2c.core.util.*;
import com.slodon.b2b2c.member.example.MemberExample;
import com.slodon.b2b2c.member.example.MemberWxsignExample;
import com.slodon.b2b2c.member.pojo.Member;
import com.slodon.b2b2c.member.pojo.MemberWxsign;
import com.slodon.b2b2c.model.business.CartModel;
import com.slodon.b2b2c.model.member.MemberLoginLogModel;
import com.slodon.b2b2c.model.member.MemberModel;
import com.slodon.b2b2c.model.member.MemberWxsignModel;
import com.slodon.b2b2c.model.msg.AppClientLogModel;
import com.slodon.b2b2c.model.msg.MemberSettingModel;
import com.slodon.b2b2c.msg.example.AppClientLogExample;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Api(tags = "front-登录管理")
@RestController
@RequestMapping("v3/member/front/login")
@Slf4j
public class LoginController extends BaseController {

    private static final String WX_AUTH_URL = "https://open.weixin.qq.com/connect/oauth2/authorize";
    private static final String WX_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
    private static final String WX_USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo";
    private static final String WX_XCX_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/jscode2session";

    @Resource
    private MemberModel memberModel;
    @Resource
    private MemberWxsignModel memberWxsignModel;
    @Resource
    private MemberLoginLogModel memberLoginLogModel;
    @Resource
    private CartModel cartModel;
    @Resource
    private AppClientLogModel appClientLogModel;
    @Resource
    private MemberSettingModel memberSettingModel;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RabbitTemplate rabbitTemplate;

    @ApiOperation("账户注销")
    @PostMapping("remove")
    public JsonResult<Object> remove(HttpServletRequest request) {
        Member member = UserUtil.getUser(request, Member.class);
        //注销
        memberModel.removeMember(member.getMemberId());

        return SldResponse.success("注销成功");
    }

    @ApiOperation("退出登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "refreshKey", value = "登录刷新令牌"),
            @ApiImplicitParam(name = "clientId", value = "客户端身份ID app传参"),
            @ApiImplicitParam(name = "alias", value = "客户端身份别名 app传参")
    })
    @PostMapping("logout")
    public JsonResult logout(HttpServletRequest request, String clientId, String alias) {
        stringRedisTemplate.opsForValue().getOperations().delete(request.getParameter("refreshKey"));
        if (!StringUtils.isEmpty(clientId) || !StringUtils.isEmpty(alias)) {
//            app退出登录，删除clientId
            AppClientLogExample appClientLogExample = new AppClientLogExample();
            appClientLogExample.setClientId(clientId);
            appClientLogExample.setAlias(alias);
            appClientLogModel.deleteAppClientLogByExample(appClientLogExample);
        }
        return SldResponse.success("退出登录成功");
    }

    @ApiOperation("微信授权登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "source", value = "授权来源 1、H5(微信内部浏览器) 2、H5(微信小程序)；3、app；4、pc", required = true),
            @ApiImplicitParam(name = "code", value = "用户授权code，非app授权登录时必填"),
            @ApiImplicitParam(name = "openid", value = "openid，app授权登录时必填"),
            @ApiImplicitParam(name = "unionid", value = "unionid，app授权登录时必填"),
            @ApiImplicitParam(name = "cartInfo", value = "离线购物车信息 如 [{\"productId\":1,\"buyNum\":1},{\"productId\":2,\"buyNum\":2}]"),
            @ApiImplicitParam(name = "userInfo", value = "用户信息,小程序、app时必传 如:{\" nickname\": \"ming\",\"sex\":\"1\",\"province\":\"PROVINCE\",\"city\":\"CITY\",\"country\":\"COUNTRY\",\"headimgurl\":\"http://thirdwx.qlogo.cn/mmopen\"}")
    })
    @PostMapping("wechat/login")
    public JsonResult wxGetAT(HttpServletRequest request, Integer source, String code, String openid,
                              String unionid, String cartInfo, String userInfo) throws Exception {
        AssertUtil.isTrue(StringUtil.isNullOrZero(source) || source > 4, "非法来源");

        String resp;
        //用户信息
        JSONObject userInfoJson;
        String appId;
        String secret;

        switch (source) {
            case 1:
                appId = stringRedisTemplate.opsForValue().get("login_wx_dev_appid");
                secret = stringRedisTemplate.opsForValue().get("login_wx_dev_appsecret");
                //微信内部浏览器
                resp = HttpClientUtil.httpGet(WX_ACCESS_TOKEN_URL + "?appid=" + appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code");
                if (null != JSONObject.parseObject(resp).getInteger("errcode")) {
                    return SldResponse.fail(JSONObject.parseObject(resp).getString("errmsg"));
                }
                //获取openid和unionid
                String accessToken = JSONObject.parseObject(resp).getString("access_token");
                openid = JSONObject.parseObject(resp).getString("openid");
                //获取userInfo
                userInfoJson = JSONObject.parseObject(HttpClientUtil.httpGet(WX_USER_INFO_URL + "?access_token=" + accessToken + "&openid=" + openid));
                if (null != JSONObject.parseObject(HttpClientUtil.httpGet(WX_USER_INFO_URL + "?access_token=" + accessToken + "&openid=" + openid)).getInteger("errcode")) {
                    return SldResponse.fail(JSONObject.parseObject(HttpClientUtil.httpGet(WX_USER_INFO_URL + "?access_token=" + accessToken + "&openid=" + openid)).getString("errmsg"));
                }
                unionid = userInfoJson.getString("unionid");
                userInfoJson.put("openid", openid);
                //性别
                userInfoJson.put("gender", userInfoJson.getString("sex"));
                //头像
                userInfoJson.put("avatarUrl", userInfoJson.getString("headimgurl"));
                break;
            case 2:
                appId = stringRedisTemplate.opsForValue().get("login_wx_mini_appid");
                secret = stringRedisTemplate.opsForValue().get("login_wx_mini_appsecret");
                //小程序
                resp = HttpClientUtil.httpGet(WX_XCX_ACCESS_TOKEN_URL + "?appid=" + appId + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code");
                if (null != JSONObject.parseObject(resp).getInteger("errcode")) {
                    return SldResponse.fail(JSONObject.parseObject(resp).getString("errmsg"));
                }
                //获取openid和unionid
                openid = JSONObject.parseObject(resp).getString("openid");
                unionid = JSONObject.parseObject(resp).getString("unionid");
                userInfoJson = JSONObject.parseObject(userInfo);
                userInfoJson.put("openid", openid);
                userInfoJson.put("unionid", unionid);
                userInfoJson.put("session_key", JSONObject.parseObject(resp).getString("session_key"));
                break;
            case 3:
                //app
                AssertUtil.notEmpty(openid, "openid不能为空");
                AssertUtil.notEmpty(unionid, "unionid不能为空");
                userInfoJson = JSONObject.parseObject(userInfo);
                userInfoJson.put("openid", openid);
                userInfoJson.put("unionid", unionid);
                break;
            case 4:
                //pc
                appId = stringRedisTemplate.opsForValue().get("login_wx_pc_appid");
                secret = stringRedisTemplate.opsForValue().get("login_wx_pc_appsecret");
                //微信内部浏览器
                resp = HttpClientUtil.httpGet(WX_ACCESS_TOKEN_URL + "?appid=" + appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code");
                if (null != JSONObject.parseObject(resp).getInteger("errcode")) {
                    return SldResponse.fail(JSONObject.parseObject(resp).getString("errmsg"));
                }
                //获取openid和unionid
                accessToken = JSONObject.parseObject(resp).getString("access_token");
                openid = JSONObject.parseObject(resp).getString("openid");
                //获取userInfo
                userInfoJson = JSONObject.parseObject(HttpClientUtil.httpGet(WX_USER_INFO_URL + "?access_token=" + accessToken + "&openid=" + openid));
                if (null != JSONObject.parseObject(HttpClientUtil.httpGet(WX_USER_INFO_URL + "?access_token=" + accessToken + "&openid=" + openid)).getInteger("errcode")) {
                    return SldResponse.fail(JSONObject.parseObject(HttpClientUtil.httpGet(WX_USER_INFO_URL + "?access_token=" + accessToken + "&openid=" + openid)).getString("errmsg"));
                }
                unionid = userInfoJson.getString("unionid");
                userInfoJson.put("openid", openid);
                break;
            default:
                return SldResponse.fail("授权失败");
        }
        //判断大写昵称是否有值，没有则复制小写
        if (StringUtil.isEmpty(userInfoJson.getString("nickName"))) {
            //昵称
            userInfoJson.put("nickName", userInfoJson.getString("nickname"));
        }
        log.info("---------------------------------------------------------");
        log.info(source + ":" + userInfoJson);
        log.info("---------------------------------------------------------");
        //查询是否已为绑定会员
        if (null != unionid) {
            MemberExample example = new MemberExample();
            example.setWxUnionid(unionid);
            List<Member> memberList = memberModel.getMemberList(example, null);
            if (!CollectionUtils.isEmpty(memberList)) {
                Member member = memberList.get(0);
                this.checkLoginMember(member);
                //更新会员信息
                this.updateWxMember(userInfoJson, member.getMemberId());
                //离线购物车信息入库
                if (!StringUtils.isEmpty(cartInfo)) {
                    List<Cart> cartList = JSONObject.parseArray(cartInfo, Cart.class);
                    cartModel.addCartByMemberId(cartList, member.getMemberId());
                }
                return createToken(member);
            }
        } else {
            MemberWxsignExample example = new MemberWxsignExample();
            example.setOpenid(openid);
            List<MemberWxsign> memberWxsignList = memberWxsignModel.getMemberWxsignList(example, null);
            if (!CollectionUtils.isEmpty(memberWxsignList)) {
                MemberWxsign memberWxsign = memberWxsignList.get(0);
                Member member = memberModel.getMemberByMemberId(memberWxsign.getMemberId());
                if (null != member) {
                    this.checkLoginMember(member);
                    //更新会员信息
                    this.updateWxMember(userInfoJson, member.getMemberId());
                    //离线购物车信息入库
                    if (!StringUtils.isEmpty(cartInfo)) {
                        List<Cart> cartList = JSONObject.parseArray(cartInfo, Cart.class);
                        cartModel.addCartByMemberId(cartList, member.getMemberId());
                    }

                    return createToken(member);
                }
            }
        }

        //新授权账号，提示绑定手机号
        HashMap<String, String> map = new HashMap<>(2);
        //true-已有授权账号，直接登录;false-新授权账号，需要绑定手机号
        map.put("redirect", "false");
        UUID uuid = UUID.randomUUID();
        stringRedisTemplate.opsForValue().set(uuid.toString(), JSONObject.toJSONString(userInfoJson), 60 * 1000, TimeUnit.SECONDS);
        map.put("bindKey", uuid.toString());
        return SldResponse.success(map);
    }

    /**
     * wx授权登录更新会员信息
     *
     * @param userInfoJson
     * @param memberId
     */
    private void updateWxMember(JSONObject userInfoJson, Integer memberId) {
        Member updateMember = new Member();
        updateMember.setMemberId(memberId);
        String nickName = new String(userInfoJson.getString("nickName").getBytes(), StandardCharsets.UTF_8);
        updateMember.setMemberNickName(nickName);
        updateMember.setGender(userInfoJson.getIntValue("gender"));
        updateMember.setWxUnionid(userInfoJson.getString("unionid"));
        updateMember.setMemberAvatar(userInfoJson.getString("avatarUrl"));
        updateMember.setWxAvatarImg(userInfoJson.getString("avatarUrl"));
        updateMember.setUpdateTime(new Date());
        memberModel.updateMember(updateMember);
    }

    /**
     * 检测登录用户是否可用
     *
     * @param memberDb
     */
    private void checkLoginMember(Member memberDb) {
        if (memberDb.getState() != MemberConst.STATE_1) {
            throw new MallException("账号不可用");
        }
        if (StringUtil.isEmpty(memberDb.getMemberMobile())) {
            throw new MallException("请绑定手机号", ResponseConst.STATE_SPECIAL);
        }
    }

    @ApiOperation("授权登录绑定手机号")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "bindType", value = "绑定方式，默认 1==去绑定，检测手机号是否已绑定其他账号；2==继续绑定，新增一条会员信息；3==更新信息，更新原会员的微信信息", defaultValue = "1"),
            @ApiImplicitParam(name = "mobile", value = "将绑定的手机号", required = true),
            @ApiImplicitParam(name = "smsCode", value = "将绑定的手机号验证码", required = true),
            @ApiImplicitParam(name = "resource", value = "来源 1、pc 2、app；3、公众号或微信内部浏览器；4、小程序", required = true),
            @ApiImplicitParam(name = "bindKey", value = "用户信息code", required = true),
            @ApiImplicitParam(name = "cartInfo", value = "离线购物车信息 如 [{\"productId\":1,\"buyNum\":1},{\"productId\":2,\"buyNum\":2}]"),
    })
    @PostMapping("wechat/bindMobile")
    public JsonResult bindWxMember(HttpServletRequest request, Integer bindType, String mobile, String smsCode,
                                   Integer resource, String bindKey, String cartInfo) {
        //从redis中获取微信用户信息
        String wxUserInfo = stringRedisTemplate.opsForValue().get(bindKey);
        AssertUtil.isTrue(StringUtils.isEmpty(wxUserInfo), "绑定失败，请重新授权登录");
        AssertUtil.isTrue(StringUtils.isEmpty(mobile), "请确认手机号信息");

        if (!(resource == 4 && StringUtils.isEmpty(smsCode))) {
            //小程序可以直接获取手机号，此时没有手机验证码，不校验
            //开关开启需要验证
            String verifyCodeCheck = stringRedisTemplate.opsForValue().get("verification_code_check_is_enable");
            if ("1".equals(verifyCodeCheck)) {
                String smsNumber = stringRedisTemplate.opsForValue().get(mobile);
                AssertUtil.isTrue(smsNumber == null || !smsNumber.equalsIgnoreCase(smsCode), "短信验证码不正确");
            }
        }

        JSONObject userInfoJson = JSONObject.parseObject(wxUserInfo);
        //各个来源，用户信息key不同，统一使用小程序的key
        if (resource == 3) {
            //微信内部浏览器
            //redis读取昵称需要转码处理
            String nickName = new String(userInfoJson.getString("nickName").getBytes(), StandardCharsets.UTF_8);
            //昵称
            userInfoJson.put("nickName", nickName);
            //性别
            userInfoJson.put("gender", userInfoJson.getString("sex"));
            //头像
            userInfoJson.put("avatarUrl", userInfoJson.getString("headimgurl"));
        }
        //查询会员信息
        MemberExample example = new MemberExample();
        example.setMemberMobile(mobile);
        List<Member> memberList = memberModel.getMemberList(example, null);
        if (bindType == 1) {
            //去绑定，检测手机号是否已存在
            if (!CollectionUtils.isEmpty(memberList)) {
                //手机号已被绑定
                JsonResult<Object> special = SldResponse.failSpecial("手机号已被其他账号绑定");
                special.setData(memberList.get(0).getMemberName());
                return special;
            } else {
                //手机号未绑定，新增会员
                this.wxSignAddMember(userInfoJson, mobile, WebUtil.getRealIp(request), resource);
            }
        } else if (bindType == 2) {
            //继续绑定，解除原会员的手机号绑定，新增一条会员信息
            AssertUtil.notEmpty(memberList, "会员信息为空");

            Member updateMember = new Member();
            updateMember.setMemberId(memberList.get(0).getMemberId());
            updateMember.setMemberMobile("");
            updateMember.setIsMobileVerify(MemberConst.IS_MOBILE_VERIFY_0);
            updateMember.setUpdateTime(new Date());
            memberModel.updateMember(updateMember);

            // 初始化会员信息
            this.wxSignAddMember(userInfoJson, mobile, WebUtil.getRealIp(request), resource);
        } else {
            //更新信息，更新原会员的微信信息
            AssertUtil.notEmpty(memberList, "会员信息为空");
            //检测要绑定的账号是否可用
            this.checkLoginMember(memberList.get(0));

            //redis读取昵称需要转码处理
            String nickName = new String(userInfoJson.getString("nickName").getBytes(), StandardCharsets.UTF_8);

            Member updateMember = new Member();
            updateMember.setMemberId(memberList.get(0).getMemberId());
            updateMember.setMemberNickName(nickName);
            updateMember.setGender(userInfoJson.getIntValue("gender"));
            updateMember.setWxUnionid(userInfoJson.getString("unionid"));
            updateMember.setMemberAvatar(userInfoJson.getString("avatarUrl"));
            updateMember.setWxAvatarImg(userInfoJson.getString("avatarUrl"));
            updateMember.setUpdateTime(new Date());
            memberModel.updateMember(updateMember);

            //新增或更新 openId 信息
            MemberWxsign wxsignNewOrUpdate = new MemberWxsign();
            wxsignNewOrUpdate.setMemberId(memberList.get(0).getMemberId());
            wxsignNewOrUpdate.setOpenid(userInfoJson.getString("openid"));
            wxsignNewOrUpdate.setResource(resource);
            memberWxsignModel.saveMemberWxsign(wxsignNewOrUpdate);
        }

        //执行登录
        Member member = memberLoginLogModel.memberLoginByMobile(mobile, WebUtil.getRealIp(request), resource);
        AssertUtil.notNull(member, "授权登录失败");

        //离线购物车信息入库
        if (!StringUtils.isEmpty(cartInfo)) {
            List<Cart> cartList = JSONObject.parseArray(cartInfo, Cart.class);
            cartModel.addCartByMemberId(cartList, member.getMemberId());
        }
        stringRedisTemplate.opsForValue().getOperations().delete(bindKey);
        return createToken(member);
    }


    @ApiOperation("手机号免密登录接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mobile", value = "手机号", required = true),
            @ApiImplicitParam(name = "smsCode", value = "短信验证码", required = true),
            @ApiImplicitParam(name = "cartInfo", value = "离线购物车信息 如 [{\"productId\":1,\"buyNum\":1},{\"productId\":2,\"buyNum\":2}]")
    })
    @PostMapping("freeSecretLogin")
    public JsonResult freeSecretLogin(HttpServletRequest request, String mobile, String smsCode, String cartInfo) {
        AssertUtil.notEmpty(mobile, "手机号不能为空");

        //开关开启需要验证
        String verifyCodeCheck = stringRedisTemplate.opsForValue().get("verification_code_check_is_enable");
        if ("1".equals(verifyCodeCheck)) {
            String smsNumber = stringRedisTemplate.opsForValue().get(mobile);
            AssertUtil.isTrue(smsNumber == null || !smsNumber.equalsIgnoreCase(smsCode), "短信验证码不正确");
        }

        String ip = WebUtil.getRealIp(request);
        // 登录验证
        Member member = memberLoginLogModel.memberLoginByMobile(mobile, ip, MemberConst.MEMBER_FROM_H5);
        AssertUtil.notNull(member, "授权登录失败");

        //离线购物车信息入库
        if (!StringUtils.isEmpty(cartInfo)) {
            List<Cart> cartList = JSONObject.parseArray(cartInfo, Cart.class);
            cartModel.addCartByMemberId(cartList, member.getMemberId());
        }
        return createToken(member);
    }

    /**
     * 微信授权登录新增会员
     *
     * @param userInfoJson
     * @param mobile
     * @param ip
     * @param resource
     */
    private void wxSignAddMember(JSONObject userInfoJson, String mobile, String ip, Integer resource) {
        // 初始化会员信息
        Member memberNew = new Member();
        memberNew.setMemberName(GoodsIdGenerator.getMemberName());
        memberNew.setMemberNickName(userInfoJson.getString("nickName"));
        memberNew.setGender(userInfoJson.getIntValue("gender"));
        memberNew.setWxUnionid(userInfoJson.getString("unionid"));
        memberNew.setMemberAvatar(userInfoJson.getString("avatarUrl"));
        memberNew.setWxAvatarImg(userInfoJson.getString("avatarUrl"));
        memberNew.setLoginPwd("");

        memberNew.setGrade(0);
        memberNew.setRegisterTime(new Date());
        memberNew.setExperienceValue(0);
        memberNew.setMemberMobile(mobile);
        memberNew.setMemberIntegral(0);
        memberNew.setLastLoginIp(ip);
        memberNew.setLastLoginTime(new Date());
        memberNew.setLoginNumber(1);
        memberNew.setLoginErrorCount(0);
        memberNew.setPayErrorCount(0);
        memberNew.setRegisterChannel(resource);
        memberNew.setBalanceAvailable(new BigDecimal("0.00"));
        memberNew.setBalanceFrozen(new BigDecimal("0.00"));
        memberNew.setPayPwd("");
        memberNew.setIsEmailVerify(MemberConst.IS_EMAIL_VERIFY_0);
        memberNew.setIsMobileVerify(MemberConst.IS_MOBILE_VERIFY_1);
        memberNew.setIsReceiveSms(1);
        memberNew.setIsReceiveEmail(1);
        memberNew.setState(MemberConst.STATE_1);
        memberNew.setIsAllowBuy(MemberConst.IS_ALLOW_BUY_1);
        memberNew.setIsAllowAsk(MemberConst.IS_ALLOW_ASK_1);
        memberNew.setIsAllowComment(MemberConst.IS_ALLOW_COMMENT_1);
        memberNew.setMemberEmail("");
        memberNew.setUpdateTime(new Date());

        //判断用户名是否已存在
        MemberExample example = new MemberExample();
        example.setMemberName(memberNew.getMemberName());
        List<Member> byNameList = memberModel.getMemberList(example, null);
        if (byNameList != null && byNameList.size() > 0) {
            List<Member> byName;
            String name = memberNew.getMemberName();
            boolean flag = true;
            int i = 0;
            while (flag) {
                example.setMemberName(name + i);
                byName = memberModel.getMemberList(example, null);
                if (byName.isEmpty()) {
                    flag = false;
                    memberNew.setMemberName(name + i);
                }
                i++;
            }
        }

        Integer memberId = memberModel.saveMember(memberNew);

        //设置openId
        MemberWxsign wxsign = new MemberWxsign();
        wxsign.setMemberId(memberNew.getMemberId());
        wxsign.setOpenid(userInfoJson.getString("openid"));
        wxsign.setResource(resource);
        memberWxsignModel.saveMemberWxsign(wxsign);

        //插入会员接收消息设置
        memberSettingModel.insertMemberSetting(memberId);

    }

    /**
     * 生成token
     *
     * @param member
     * @return
     */
    public JsonResult createToken(Member member) {
        //登陆
        //设置请求头
        Map<String, String> headers = new HashMap<>(16);
        headers.put("Authorization", "Basic ZnJvbnQ6ZnJvbnQ=");
        headers.put("name", null);

        //开关开启需要验证
        String verifyCodeCheck = stringRedisTemplate.opsForValue().get("verification_code_check_is_enable");
        String password = "";
        if ("1".equals(verifyCodeCheck)) {
            UUID uuid = UUID.randomUUID();
            stringRedisTemplate.opsForValue().set(member.getMemberMobile(), uuid.toString(), 60 * 1000, TimeUnit.SECONDS);
            password = uuid.toString();
        } else {
            password = "888888";
        }
        //设置请求参数
        UrlQuery urlQuery = new UrlQuery();
        urlQuery.add("loginType", 2);
        urlQuery.add("username", member.getMemberMobile());
        urlQuery.add("password", password);
        urlQuery.add("grant_type", "password");

        URI uri;
        try {
            uri = new URI(DomainUrlUtil.SLD_H5_URL + "/v3/frontLogin/oauth/token");
        } catch (URISyntaxException e) {
            log.error("登录地址有误", e);
            throw new MallException("登录失败");
        }
        UrlBuilder urlBuilder = UrlBuilder.of(uri, Charset.defaultCharset()).setQuery(urlQuery);

        HttpResponse execute = new HttpRequest(urlBuilder).method(Method.POST).addHeaders(headers).execute();
        return JSONObject.parseObject(execute.body(), JsonResult.class);
    }

    @ApiOperation("获取wxjsapi配置接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "source", value = "source 来源 1、H5(微信内部浏览器+公众号) 2、H5(微信小程序)；3、app", required = true),
            @ApiImplicitParam(name = "url", value = "来源页面url")
    })
    @GetMapping("wxjsConf")
    public JsonResult<Object> wxjsConf(HttpServletRequest request, Integer source, String url) {
        //获取access_token地址
        final String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        //获取ticket地址
        final String ticketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
        //reids中缓存ticket
        final String ticketRedisKey = "wx_share_ticket";
        //配置信息
        String appsecret;
        //配置信息
        String appid;
        //生成签名随机串
        String nonceStr = UUID.randomUUID().toString();
        //生成签名的时间戳
        Long timestamp = System.currentTimeMillis() / 1000;
        //缓存中的ticket信息
        String ticket = stringRedisTemplate.opsForValue().get(ticketRedisKey);

        switch (source) {
            case 1:
                appid = stringRedisTemplate.opsForValue().get("login_wx_dev_appid");
                appsecret = stringRedisTemplate.opsForValue().get("login_wx_dev_appsecret");
                break;
            case 2:
                appid = stringRedisTemplate.opsForValue().get("login_wx_mini_appid");
                appsecret = stringRedisTemplate.opsForValue().get("login_wx_mini_appsecret");
                break;
            default:
                appid = "";
                appsecret = "";
        }

        if (ticket == null) {
            //无缓存，重新生成一个 ticket
            //获取accessToken
            String accessTokenResp = HttpUtil.get(accessTokenUrl.replace("APPID", appid).replace("APPSECRET", appsecret));
            JSONObject accessTokenJsonObject = JSONObject.parseObject(accessTokenResp);
            if (null != accessTokenJsonObject.getInteger("errcode")) {
                //获取accessToken失败
                return SldResponse.fail(accessTokenJsonObject.getString("errmsg"));
            }
            String accessToken = accessTokenJsonObject.getString("access_token");
            //accessToken的过期时间
            int accessTokenExpiresIn = accessTokenJsonObject.getIntValue("expires_in");

            //获取ticket
            String ticketResp = HttpUtil.get(ticketUrl.replace("ACCESS_TOKEN", accessToken));
            JSONObject ticketJsonObject = JSONObject.parseObject(ticketResp);
            if (!ticketJsonObject.getInteger("errcode").equals(0)) {
                return SldResponse.fail(ticketJsonObject.getString("errmsg"));
            }
            ticket = ticketJsonObject.getString("ticket");
            //ticket的过期时间
            int ticketExpiresIn = ticketJsonObject.getIntValue("expires_in");

            //缓存ticket,过期时间为accessToken和ticket中过期时间较小的一个
            stringRedisTemplate.opsForValue().set(ticketRedisKey, ticket, Long.min(accessTokenExpiresIn, ticketExpiresIn), TimeUnit.SECONDS);
        }

        String signature = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "&timestamp=" + timestamp + "&url=" + url;
        log.debug("-------------------------------------------------------");
        log.debug(signature);
        log.debug("-------------------------------------------------------");
        //sha1加密
        signature = DigestUtils.sha1Hex(signature);

        HashMap<String, Object> data = new HashMap<>();
        //appid
        data.put("appId", appid);
        //签名
        data.put("signature", signature);
        //生成签名的随机串
        data.put("nonceStr", nonceStr);
        //生成签名的时间戳
        data.put("timestamp", timestamp);
        return SldResponse.success(data);
    }

    @ApiOperation("获取微信openId")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "source", value = "终端类型 1、H5(微信内部浏览器) 2、H5(微信小程序)", required = true),
            @ApiImplicitParam(name = "code", value = "用户授权code", required = true)
    })
    @PostMapping("wechat/getOpenId")
    public JsonResult<Object> getOpenId(HttpServletRequest request, Integer source, String code) throws Exception {
        switch (source) {
            case 1:
                String appId = stringRedisTemplate.opsForValue().get("login_wx_dev_appid");
                String secret = stringRedisTemplate.opsForValue().get("login_wx_dev_appsecret");
                //微信内部浏览器
                String resp = HttpClientUtil.httpGet(WX_ACCESS_TOKEN_URL + "?appid=" + appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code");
                if (null != JSONObject.parseObject(resp).getInteger("errcode")) {
                    return SldResponse.fail(JSONObject.parseObject(resp).getString("errmsg"));
                }
                //获取openid
                return SldResponse.success(JSONObject.parseObject(resp).get("openid"));
            case 2:
                appId = stringRedisTemplate.opsForValue().get("login_wx_mini_appid");
                secret = stringRedisTemplate.opsForValue().get("login_wx_mini_appsecret");
                //小程序
                resp = HttpClientUtil.httpGet(WX_XCX_ACCESS_TOKEN_URL + "?appid=" + appId + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code");
                if (null != JSONObject.parseObject(resp).getInteger("errcode")) {
                    return SldResponse.fail(JSONObject.parseObject(resp).getString("errmsg"));
                }
                //获取openid
                return SldResponse.success(JSONObject.parseObject(resp).get("openid"));
            default:
                return SldResponse.fail("终端类型有误");
        }
    }

    @ApiOperation("微信小程序获取微信用户绑定的手机号")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "encryptedData", value = "包括敏感数据在内的完整用户信息的加密数据", required = true),
            @ApiImplicitParam(name = "iv", value = "加密算法的初始向量", required = true),
            @ApiImplicitParam(name = "code", value = "用户授权code", required = true)
    })
    @PostMapping("wechat/getMobile")
    public JsonResult<Object> getMobile(HttpServletRequest request, String code, String encryptedData, String iv) throws Exception {

        String appId = stringRedisTemplate.opsForValue().get("login_wx_mini_appid");
        String secret = stringRedisTemplate.opsForValue().get("login_wx_mini_appsecret");
        //小程序
        String resp = HttpClientUtil.httpGet(WX_XCX_ACCESS_TOKEN_URL + "?appid=" + appId + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code");

        if (null != JSONObject.parseObject(resp).getInteger("errcode")) {
            return SldResponse.fail(JSONObject.parseObject(resp).getString("errmsg"));
        }
        //获取 sessionKey
        String sessionKey = JSONObject.parseObject(resp).getString("session_key");

        //解密
        // 被加密的数据
        byte[] dataByte = org.apache.commons.codec.binary.Base64.decodeBase64(encryptedData);
        // 加密秘钥
        byte[] keyByte = org.apache.commons.codec.binary.Base64.decodeBase64(sessionKey);
        // 偏移量
        byte[] ivByte = org.apache.commons.codec.binary.Base64.decodeBase64(iv);

        try {
            // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + 1;
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            // 初始化
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, StandardCharsets.UTF_8);
                return SldResponse.success(JSONObject.parseObject(result));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return SldResponse.fail("获取手机号失败");
    }
}
