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.SessionObject;
import com.hai.common.security.UserCenter;
import com.hai.common.utils.HttpsUtils;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

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 HighUserPayPasswordService highUserPayPasswordService;

    @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 = "/login", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "小程序授权用户登录接口")
    public ResponseData login(@RequestParam(value = "openId", required = true) String openId,
                              HttpServletRequest request, HttpServletResponse response) {
        try {
            //校验code,openId不能同时为空
            if (StringUtils.isEmpty(openId)) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.REQ_PARAMS_ERROR, "");
            }
            HighUser highUser = highUserService.findByOpenId(openId);
            if (highUser == null) {
                log.error("login error!", "未找到用户");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.UN_MEMBER_ERROR, "");
            }

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

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

    @RequestMapping(value = "/getPhoneNumber", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "小程序获取用户手机号码")
    public ResponseData getPhoneNumber(@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 {
            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.bindUserPhone(phoneNoInfo.getPurePhoneNumber(), request);

            // 定义个人所有数据
            HighUserModel highUserModel = new HighUserModel();
            HighUser detailData = highUserService.getDetailDataByUser(user.getId());
            detailData.setPassword(null);
            highUserModel.setHighUser(detailData);
            SessionObject so = new SessionObject(user.getUnionId(), 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 {
            //校验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解析失败");
            }
            if (StringUtils.isBlank(session.getUnionid())) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.WECHAT_DECRYPT_ERROR, "获取UnionId失败");
            }
            HighUser user = highUserService.findByOpenId(session.getOpenid());
            if (user == null) {
                user = new HighUser();
                user.setUnionId(session.getUnionid());
                user.setOpenId(openId);
                user.setRegTime(new Date());
                user.setStatus(1);
                user.setGold(0);
                user.setHeaderImg(userInfo.getAvatarUrl());
                user.setName(userInfo.getNickName());
                highUserService.insertUser(user);
            } else {
                user.setUnionId(session.getUnionid());
                user.setHeaderImg(userInfo.getAvatarUrl());
                user.setName(userInfo.getNickName());
                user.setOpenId(userInfo.getOpenId());
                highUserService.updateUser(user);
            }

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

            return ResponseMsgUtil.success(so);

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


    @RequestMapping(value = "/getH5Code", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "【H5】获取Code")
    public ResponseData getH5Code() {
        try {
            Map<String, Object> params = new LinkedHashMap<>();
            params.put("appid", SysConst.getSysConfig().getWxH5AppId());
            params.put("redirect_uri", URLEncoder.encode("https://hsgcs.dctpay.com/H5/index.html#/", "utf-8"));
            //params.put("redirect_uri", "https://hsgcs.dctpay.com/H5/index.html#/");
            params.put("response_type", "code");
            params.put("scope", "snsapi_userinfo");
            params.put("state", "STATE");

            String apiUrl = "https://open.weixin.qq.com/connect/oauth2/authorize";
            StringBuffer param = new StringBuffer();
            int i = 0;
            for (String key : params.keySet()) {
                if (i == 0)
                    param.append("?");
                else
                    param.append("&");
                param.append(key).append("=").append(params.get(key));
                i++;
            }
            apiUrl += param + "#wechat_redirect";
            return ResponseMsgUtil.success(apiUrl);

        } 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 = "/getH5UserInfo", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "【H5】获取用户信息")
    public ResponseData getH5UserInfo(@RequestParam(value = "code", required = true) String code,
                                      HttpServletRequest request, HttpServletResponse response) {
        try {

            // 获取access_token
            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");
            JSONObject jsonObject = HttpsUtils.doGet("https://api.weixin.qq.com/sns/oauth2/access_token", params);
            String accessToken = jsonObject.getString("access_token");
            String openid = jsonObject.getString("openid");
            if (StringUtils.isBlank(accessToken) || StringUtils.isBlank(openid)) {
                log.error("getH5UserInfo error!", "获取微信access_token失败"  );
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "获取微信access_token失败");
            }
            params.clear();
            params.put("access_token", accessToken);
            params.put("openid", openid);
            params.put("lang", "zh_CN");
            JSONObject userInfo = HttpsUtils.doGet("https://api.weixin.qq.com/sns/userinfo", params);
            if (StringUtils.isNotBlank(userInfo.getString("errcode"))) {
                log.error("getH5UserInfo error!", "获取微信用户信息失败");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "获取微信用户信息失败");
            }
            if (StringUtils.isBlank(userInfo.getString("unionid"))) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.WECHAT_DECRYPT_ERROR, "获取UnionId失败");
            }

            HighUser user = highUserService.findByUnionId(userInfo.getString("unionid"));
            if (user == null) {
                user = new HighUser();
                user.setUnionId(userInfo.getString("unionid"));
                user.setOpenIdH5(openid);
                user.setRegTime(new Date());
                user.setStatus(1);
                user.setGold(0);
                user.setHeaderImg(userInfo.getString("headimgurl"));
                user.setName(userInfo.getString("nickname"));
                highUserService.insertUser(user);
            } else {
                user.setOpenIdH5(openid);
                user.setHeaderImg(userInfo.getString("headimgurl"));
                user.setName(userInfo.getString("nickname"));
                highUserService.updateUser(user);
            }

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

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


    @RequestMapping(value = "/getUnionId", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "刷取unionid")
    public ResponseData getUnionId(HttpServletRequest request, HttpServletResponse response) {
        try {
            // 获取access_token
            Map<String, Object> params = new HashMap<>();
            params.put("appid", SysConst.getSysConfig().getWxAppId());
            params.put("secret", SysConst.getSysConfig().getWxAppSecret());
            params.put("grant_type", "client_credential");
            JSONObject jsonObject = HttpsUtils.doGet("https://api.weixin.qq.com/cgi-bin/token", params);
            System.out.println(jsonObject.toJSONString());
            String accessToken = jsonObject.getString("access_token");
            if (StringUtils.isBlank(accessToken)) {
                log.error("getH5UserInfo error!", "获取微信access_token失败"  );
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "获取微信access_token失败");
            }
            params.clear();
            List<Map<String,Object>> userMapList = new ArrayList<>();
            Map<String,Object> userMap;
            int pageNum = 1;
            while (true) {
                userMapList.clear();;
                PageHelper.startPage(pageNum, 100);
                PageInfo<HighUser> pageInfo = new PageInfo<>(highUserService.getListUser(new HashMap<>()));
                if (pageInfo.getList().size() > 0) {
                    for (HighUser user : pageInfo.getList()) {
                        userMap = new HashMap<>();
                        userMap.put("openid", user.getOpenId());
                        userMap.put("lang", "zh_CN");
                        userMapList.add(userMap);
                    }

                    params.put("user_list", userMapList);
                    System.out.println(JSONObject.toJSONString(params));
                    JSONObject userInfo = HttpsUtils.doPost("https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=" + accessToken, JSONObject.toJSONString(params));
                    System.out.println(userInfo.toJSONString());
                }
                pageNum++;
                break;
            }

            return ResponseMsgUtil.success("处理成功");

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


}
