package com.cweb.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.alibaba.fastjson.JSONObject;
import com.cweb.config.SessionKeyCache;
import com.cweb.config.SysConst;
import com.cweb.config.WxMaConfiguration;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hai.common.exception.ErrorCode;
import com.hai.common.exception.ErrorHelp;
import com.hai.common.exception.SysCode;
import com.hai.common.security.*;
import com.hai.common.utils.HttpsUtils;
import com.hai.common.utils.IDGenerator;
import com.hai.common.utils.RedisUtil;
import com.hai.common.utils.ResponseMsgUtil;
import com.hai.entity.HighUser;
import com.hai.model.HighUserModel;
import com.hai.model.ResponseData;
import com.hai.service.HighUserPayPasswordService;
import com.hai.service.HighUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.*;

@Controller
@RequestMapping(value = "/wechat")
@Api(value = "微信授权")
public class WechatController {

    private static final Logger log = LoggerFactory.getLogger(WechatController.class);

    private static final String WX_OPENID_SESSION_REDIS = "WX_OPENID_SESSION_REDIS";

    @Autowired
    private UserCenter userCenter;

    @Resource
    private HighUserService highUserService;

    @Resource
    private RedisUtil redisUtil;

    @RequestMapping(value = "/handleCode", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "小程序code解析")
    public ResponseData compairCode(@RequestParam(value = "code", required = true) String code,
                                    HttpServletRequest request, HttpServletResponse response) {
        try {
            //校验code,openId不能同时为空
            if (StringUtils.isEmpty(code)) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.REQ_PARAMS_ERROR, "");
            }
            //请求微信api，获取用户session_key以及openId
            final WxMaService wxService = WxMaConfiguration.getMaService();
            WxMaJscode2SessionResult session = wxService.jsCode2SessionInfo(code);
            //保存小程序用户登录的openId及sessionKey信息
            redisUtil.hset(WX_OPENID_SESSION_REDIS, session.getOpenid(), session);
            JSONObject jo = new JSONObject();
            jo.put("openId", session.getOpenid());
            return ResponseMsgUtil.success(jo);
        } catch (Exception e) {
            return ResponseMsgUtil.exception(e);
        }
    }

    @RequestMapping(value = "/loginByPhone", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "小程序根据手机号登录或注册")
    public ResponseData loginByPhone(@RequestParam(value = "encryptedData", required = true) String encryptedData,
                                     @RequestParam(value = "iv", required = true) String iv,
                                     @RequestParam(value = "openId", required = true) String openId,
                                     @RequestParam(value = "popularizeUserId", required = false) Long popularizeUserId,
                                     @RequestParam(value = "regionId", required = false) String regionId,
                                     HttpServletRequest request, HttpServletResponse response) {
        try {
            log.error("origin encryptedData:" + encryptedData + ";iv:" + iv);
            //校验openId不能为空
            //encryptedData,iv与unionId不能同时为空
            encryptedData = encryptedData.replace(" ", "+");
            iv = iv.replace(" ", "+");
            log.error("dest encryptedData:" + encryptedData + ";iv:" + iv);
            if (StringUtils.isEmpty(openId)
                    || StringUtils.isEmpty(encryptedData) || StringUtils.isEmpty(iv)) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.REQ_PARAMS_ERROR, "");
            }
            //请求微信api，获取用户session_key以及openId
            Object skObject = redisUtil.hget(WX_OPENID_SESSION_REDIS, openId);
            if (skObject == null) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.WECHAT_LOGIN_ERROR);
            }
            WxMaJscode2SessionResult session = (WxMaJscode2SessionResult) skObject;

            final WxMaService wxService = WxMaConfiguration.getMaService();
            WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), encryptedData, iv);
            if (phoneNoInfo == null || StringUtils.isEmpty(phoneNoInfo.getPurePhoneNumber())) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.WECHAT_DECRYPT_ERROR, "用户phoneNumber解析失败");
            }

            // 根据手机号查询用户
            HighUser user = highUserService.findByPhone(phoneNoInfo.getPurePhoneNumber());
            if (user == null) {
                user = new HighUser();
                user.setName("用户" + IDGenerator.nextId(5));
                user.setPhone(phoneNoInfo.getPurePhoneNumber());
                user.setRegTime(new Date());
                user.setGold(0);
                user.setOpenId(session.getOpenid());
                user.setUnionId(session.getUnionid());
                user.setStatus(1);
                // 用户信息完整状态
                // 0：完整
                // 1：需要填写用户信息
                // 2：需要填写手机号
                user.setInfoCompleteStatus(1);
                highUserService.insertUser(user , popularizeUserId , regionId);
            } else {
                if (session.getOpenid() == null) {
                    user.setOpenId(session.getOpenid());
                    user.setUnionId(session.getUnionid());
                    highUserService.updateUser(user);
                }
            }

            // 定义个人所有数据
            HighUserModel highUserModel = new HighUserModel();
            HighUser detailData = highUserService.getDetailDataByUser(user.getId());
            detailData.setPassword(null);
            highUserModel.setHighUser(detailData);
            SessionObject so = new SessionObject(user.getPhone(), 1, highUserModel);
            userCenter.save(request, response, so);

            return ResponseMsgUtil.success(so);

        } catch (Exception e) {
            return ResponseMsgUtil.exception(e);
        }
    }


    @RequestMapping(value = "/getUserInfo", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "小程序获取用户信息")
    public ResponseData getUserInfo(@RequestParam(value = "encryptedData", required = true) String encryptedData,
                                    @RequestParam(value = "iv", required = true) String iv,
                                    @RequestParam(value = "openId", required = true) String openId,
                                    HttpServletRequest request, HttpServletResponse response) {
        try {

            // 用户
            SessionObject sessionObject = userCenter.getSessionObject(request);
            HighUserModel userInfoModel = (HighUserModel) sessionObject.getObject();

            //校验openId不能为空
            //encryptedData,iv与unionId不能同时为空
            encryptedData = encryptedData.replace(" ", "+");
            iv = iv.replace(" ", "+");
            if (StringUtils.isEmpty(openId) || StringUtils.isEmpty(encryptedData) || StringUtils.isEmpty(iv)) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.REQ_PARAMS_ERROR, "");
            }
            //请求微信api，获取用户session_key以及openId
            Object skObject = redisUtil.hget(WX_OPENID_SESSION_REDIS, openId);
            if (skObject == null) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.WECHAT_LOGIN_ERROR);
            }
            WxMaJscode2SessionResult session = (WxMaJscode2SessionResult) skObject;

            final WxMaService wxService = WxMaConfiguration.getMaService();
            WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), encryptedData, iv);
            if (userInfo == null) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.WECHAT_DECRYPT_ERROR, "用户phoneNumber解析失败");
            }

            HighUser user = highUserService.findByUserId(userInfoModel.getHighUser().getId());
            if (user == null) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.COMMON_ERROR, "未找到用户信息");
            }
            // 用户信息完整状态
            // 0：完整
            // 1：需要填写用户信息
            // 2：需要填写手机号
            if (user.getInfoCompleteStatus() == 1) {
                if (StringUtils.isNotBlank(user.getPhone())) {
                    user.setInfoCompleteStatus(0);
                } else {
                    user.setInfoCompleteStatus(2);
                }
            }
            user.setName(userInfo.getNickName());
            user.setHeaderImg(userInfo.getAvatarUrl());
            highUserService.updateUser(user);

            // 定义个人所有数据
            HighUserModel highUserModel = new HighUserModel();
            HighUser detailData = highUserService.getDetailDataByUser(user.getId());
            detailData.setPassword(null);
            highUserModel.setHighUser(detailData);
            if (user.getPhone() == null) {
                log.error("login error!", "未绑定手机号");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未绑定手机号");
            }
            SessionObject so = new SessionObject(user.getPhone(), 1, highUserModel);
            userCenter.save(request, response, so);

            return ResponseMsgUtil.success(so);

        } catch (Exception e) {
            return ResponseMsgUtil.exception(e);
        }
    }

    @RequestMapping(value = "/getH5AccessToken", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "【H5】获取AccessToken")
    public ResponseData getH5AccessToken(@RequestParam(value = "code", required = true) String code) {
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("appid", SysConst.getSysConfig().getWxH5AppId());
            params.put("secret", SysConst.getSysConfig().getWxH5AppSecret());
            params.put("code", code);
            params.put("grant_type", "authorization_code");
            return ResponseMsgUtil.success(HttpsUtils.doGet("https://api.weixin.qq.com/sns/oauth2/access_token", params));

        } catch (Exception e) {
            return ResponseMsgUtil.exception(e);
        }
    }

    @RequestMapping(value = "/loginByTel", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "根据手机号码登陆")
    public ResponseData loginByTel(@RequestParam(value = "phone", required = true) String phone,
                                   @RequestParam(value = "code", required = true) String code,
                                   @RequestParam(value = "popularizeUserId", required = false) Long popularizeUserId,
                                   @RequestParam(value = "regionId", required = false) String regionId,
                                   HttpServletRequest request, HttpServletResponse response) {
        try {


            // 获取手机号验证码
            String phoneSmsCode = (String) redisUtil.get("SMS_"+ phone);

            // 验证码校验
            if (!(StringUtils.isNotBlank(phoneSmsCode) && Objects.equals(phoneSmsCode,code))) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "验证码错误");
            }

            // 根据手机号查询用户
            HighUser user = highUserService.findByPhone(phone);

            if (user == null) {
                user = new HighUser();
                user.setName("用户" + IDGenerator.nextId(5));
                user.setPhone(phone);
                user.setRegTime(new Date());
                user.setGold(0);
                user.setStatus(1);
                // 用户信息完整状态
                // 0：完整
                // 1：需要填写用户信息
                // 2：需要填写手机号
                user.setInfoCompleteStatus(1);
                highUserService.insertUser(user , popularizeUserId , regionId);
            }
            // 定义个人所有数据
            HighUserModel highUserModel = new HighUserModel();
            HighUser detailData = highUserService.getDetailDataByUser(user.getId());
            detailData.setPassword(null);
            highUserModel.setHighUser(detailData);
            SessionObject so = new SessionObject(user.getPhone(), 1, highUserModel);
            userCenter.save(request, response, so);
            return ResponseMsgUtil.success(so);

        } catch (Exception e) {
            return ResponseMsgUtil.exception(e);
        }
    }

    @RequestMapping(value = "/loginBySilence", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "根据手机号码登陆")
    public ResponseData loginByTel(@RequestParam(value = "phone", required = true) String phone,
                                   HttpServletRequest request, HttpServletResponse response) {
        try {


            // 根据手机号查询用户
            HighUser user = highUserService.findByPhone(phone);

            if (user == null) {
                user = new HighUser();
                user.setName("用户" + IDGenerator.nextId(5));
                user.setPhone(phone);
                user.setRegTime(new Date());
                user.setGold(0);
                user.setStatus(1);
                // 用户信息完整状态
                // 0：完整
                // 1：需要填写用户信息
                // 2：需要填写手机号
                user.setInfoCompleteStatus(1);
                highUserService.insertUser(user , null , null);
            }

            // 定义个人所有数据
            HighUserModel highUserModel = new HighUserModel();
            HighUser detailData = highUserService.getDetailDataByUser(user.getId());
            detailData.setPassword(null);
            highUserModel.setHighUser(detailData);
            SessionObject so = new SessionObject(user.getPhone(), 1, highUserModel);
            userCenter.save(request, response, so);
            return ResponseMsgUtil.success(so);

        } catch (Exception e) {
            return ResponseMsgUtil.exception(e);
        }
    }

    @RequestMapping(value = "/getH5AccessByOpenId", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "【H5】通过openId查询")
    public ResponseData getH5AccessByOpenId(@RequestParam(value = "openId", required = true) String openId,
                                            HttpServletRequest request, HttpServletResponse response) {
        try {

            HighUser user = highUserService.findByOpenId(openId);

            if (user == null) {
                user = new HighUser();
                user.setName("用户" + IDGenerator.nextId(5));
                user.setRegTime(new Date());
                user.setGold(0);
                user.setOpenId(openId);
                user.setStatus(1);
                // 用户信息完整状态
                // 0：完整
                // 1：需要填写用户信息
                // 2：需要填写手机号
                user.setInfoCompleteStatus(1);
                highUserService.insertUser(user , null , null);
            }

            // 定义个人所有数据
            HighUserModel highUserModel = new HighUserModel();
            HighUser detailData = highUserService.getDetailDataByUser(user.getId());
            detailData.setPassword(null);
            highUserModel.setHighUser(detailData);
            SessionObject so = new SessionObject(user.getOpenId(), 1, highUserModel);
            userCenter.save(request, response, so);
            return ResponseMsgUtil.success(so);

        } catch (Exception e) {
            return ResponseMsgUtil.exception(e);
        }
    }
}
