package com.web.controller;

import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.alibaba.fastjson.JSONObject;
import com.hai.common.exception.ErrorCode;
import com.hai.common.exception.ErrorHelp;
import com.hai.common.exception.SysCode;
import com.hai.common.security.UserCenter;
import com.hai.common.utils.*;
import com.hai.config.UnionUserConfig;
import com.hai.config.WxMaConfiguration;
import com.hai.entity.HighUser;
import com.hai.enum_type.LoginPlatform;
import com.hai.model.HighUserModel;
import com.hai.model.ResponseData;
import com.hai.service.HighUserService;
import com.web.type.LoginType;
import com.hai.enum_type.RedisFileFolder;
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.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Auther: 胡锐
 * @Description:
 * @Date: 2021/3/26 23:08
 */
@Controller
@RequestMapping(value = "/login")
@Api(value = "登录业务")
public class LoginController {

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

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private HighUserService userService;

    @Resource
    private UserCenter userCenter;

    @Resource
    private UnionUserConfig unionUserConfig;

    @RequestMapping(value = "/phone", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "手机号登录")
    public ResponseData phone(@RequestBody JSONObject body,
                              HttpServletRequest request, HttpServletResponse response) {
        try {
            if (body == null
                || StringUtils.isBlank(body.getString("platform"))
                || StringUtils.isBlank(body.getString("type"))
                || StringUtils.isBlank(body.getString("phone"))
            ) {
                log.error("LoginController --> phone() error!", "请求参数校验失败");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, "");
            }
            String phone = body.getString("phone");

            // 客户端
            LoginPlatform platform = LoginPlatform.getDataByType(body.getString("platform"));
            if (platform == null) {
                log.error("LoginController --> phone() error!", "未知客户端");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知客户端");
            }
            // 校验手机号格式
            if (MemberValidateUtil.validatePhone(phone) == false) {
                log.error("LoginController --> phone() error!", "请输入正确的手机号");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "请输入正确的手机号");
            }
            // 登录类型
            LoginType loginType = LoginType.getDataByType(body.getString("type"));
            if (loginType == null) {
                log.error("LoginController --> phone() error!", "未知登录类型；" + body.getString("type"));
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知登录类型");
            }

            if (body.getString("type").equals(LoginType.SMS.getCode())) {
                if (StringUtils.isBlank(body.getString("smsCode"))) {
                    log.error("LoginController --> phone() error!", "请输入短信验证码");
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "请输入短信验证码");
                }
                // 手机号的验证码
                Object phoneCodeObject = redisUtil.get(RedisFileFolder.SMS_CODE.getCode() + phone);
                if (phoneCodeObject == null) {
                    log.error("LoginController --> phone() error!", "短信验证码错误");
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "短信验证码错误");
                }
                if (!body.getString("smsCode").equals(phoneCodeObject.toString())) {
                    log.error("LoginController --> phone() error!", "短信验证码错误");
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "短信验证码错误");
                }
                redisUtil.del(RedisFileFolder.SMS_CODE.getCode() + phone);


                Map<String, Object> other = new HashMap<>();
                other.put("openIdH5", body.getString("openIdH5"));
                return ResponseMsgUtil.success(userService.loginAndRegister(platform, phone, body.getLong("popularizeUserId"), other, request, response));
            }

            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "登录失败");

        } catch (Exception e) {
            log.error("LoginController --> phone() error!", e);
            return ResponseMsgUtil.exception(e);
        }
    }

    @RequestMapping(value = "/openId", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "openId登录")
    public ResponseData openId(@RequestBody JSONObject body,HttpServletRequest request, HttpServletResponse response) {
        try {
            if (body == null
                    || StringUtils.isBlank(body.getString("platform"))
                    || StringUtils.isBlank(body.getString("type"))
                    || StringUtils.isBlank(body.getString("openId"))
            ) {
                log.error("LoginController --> phone() error!", "请求参数校验失败");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, "");
            }
            // 客户端
            LoginPlatform platform = LoginPlatform.getDataByType(body.getString("platform"));
            if (platform == null) {
                log.error("LoginController --> phone() error!", "未知客户端");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知客户端");
            }
            // 登录类型
            LoginType loginType = LoginType.getDataByType(body.getString("type"));
            if (loginType == null) {
                log.error("LoginController --> phone() error!", "未知登录类型；" + body.getString("type"));
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知登录类型");
            }

            if (body.getString("type").equals(LoginType.WECHAT_MP_OPENID.getCode())) {
                Map<String, Object> param = new HashMap<>();
                param.put("openId", body.getString("openId"));
                List<HighUser> userList = userService.getUserList(param);
                if (userList.size() > 0) {
                    HighUser user = userList.get(0);
                    if (StringUtils.isNotBlank(user.getPhone())){
                        return ResponseMsgUtil.success(userService.loginAndRegister(platform, user.getPhone(), body.getLong("popularizeUserId"), new HashMap<>(), request, response));
                    }
               }
                return ResponseMsgUtil.success(null);

            } else if (body.getString("type").equals(LoginType.WECHAT_MA_OPENID.getCode())) {
                Map<String, Object> param = new HashMap<>();
                param.put("openIdH5", body.getString("openId"));
                List<HighUser> userList = userService.getUserList(param);
                if (userList.size() > 0) {
                    HighUser user = userList.get(0);
                    if (StringUtils.isNotBlank(user.getPhone())) {
                        return ResponseMsgUtil.success(userService.loginAndRegister(platform, user.getPhone(), body.getLong("popularizeUserId"), new HashMap<>(), request, response));
                    }
                }
                return ResponseMsgUtil.success(null);
            }

            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "登录失败");

        } catch (Exception e) {
            log.error("LoginController --> phone() error!", e);
            return ResponseMsgUtil.exception(e);
        }
    }

    @RequestMapping(value = "/wxMiniHandleCode", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "微信小程序code解析")
    public ResponseData wxMiniHandleCode(@RequestBody JSONObject body) {
        try {
            if (body == null|| StringUtils.isBlank(body.getString("code"))) {
                log.error("LoginController --> phone() error!", "请求参数校验失败");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, "");
            }
            WxMaJscode2SessionResult session;
            if (body.getInteger("type") != null) {
                //请求微信api，获取用户session_key以及openId
                session = WxMaConfiguration.getMaService(body.getInteger("type")).jsCode2SessionInfo(body.getString("code"));
            } else {
                //请求微信api，获取用户session_key以及openId
                session = WxMaConfiguration.getMaService().jsCode2SessionInfo(body.getString("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 = "/wxMini", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "微信小程序")
    public ResponseData wxMini(@RequestBody JSONObject body,HttpServletRequest request, HttpServletResponse response) {
        try {
            if (body == null
                    || StringUtils.isBlank(body.getString("encryptedData"))
                    || StringUtils.isBlank(body.getString("iv"))
                    || StringUtils.isBlank(body.getString("openId"))) {
                log.error("LoginController --> phone() error!", "请求参数校验失败");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, "");
            }

            String encryptedData = body.getString("encryptedData").replace(" ", "+");
            String iv = body.getString("iv").replace(" ", "+");

            //请求微信api，获取用户session_key以及openId
            Object skObject = redisUtil.hget("WX_OPENID_SESSION_REDIS", body.getString("openId"));
            if (skObject == null) {
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.WECHAT_LOGIN_ERROR);
            }
            WxMaJscode2SessionResult session = (WxMaJscode2SessionResult) skObject;
            WxMaPhoneNumberInfo phoneNoInfo;
            if (body.getInteger("type") != null) {
                phoneNoInfo = WxMaConfiguration
                        .getMaService(body.getInteger("type"))
                        .getUserService()
                        .getPhoneNoInfo(session.getSessionKey(), encryptedData, iv);
            } else {
                phoneNoInfo = WxMaConfiguration
                        .getMaService()
                        .getUserService()
                        .getPhoneNoInfo(session.getSessionKey(), encryptedData, iv);
            }


            if (phoneNoInfo == null || StringUtils.isEmpty(phoneNoInfo.getPurePhoneNumber())) {
                log.error("LoginController --> wxMini() error!", "登录失败! 用户手机号解析失败");
                throw ErrorHelp.genException(SysCode.MiniProgram, ErrorCode.WECHAT_DECRYPT_ERROR, "登录失败! 用户手机号解析失败");
            }
            Map<String, Object> other = new HashMap<>();
            other.put("openId", session.getOpenid());
            return ResponseMsgUtil.success(userService.loginAndRegister(LoginPlatform.WXAPPLETS, phoneNoInfo.getPurePhoneNumber(), body.getLong("popularizeUserId"), other, request, response));

        } catch (Exception e) {
            log.error("LoginController --> wxMini() error!", e);
            return ResponseMsgUtil.exception(e);
        }
    }

    @RequestMapping(value = "/union", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "银联授权手机号登录接口")
    public ResponseData union(@RequestBody JSONObject body,HttpServletRequest request, HttpServletResponse response) {
        try {

            if (body == null || StringUtils.isBlank(body.getString("code"))) {
                log.error("LoginController --> phone() error!", "请求参数校验失败");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, "");
            }

            // 获取应用访问令牌
            String backendToken = unionUserConfig.getBackendToken();

            // 获取授权访问令牌
            JSONObject token = unionUserConfig.getAccessToken(backendToken, body.getString("code"));
            if (token == null || !token.getString("resp").equals("00")) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, token.getString("msg"));
            }

            // 获取用户手机号
            JSONObject userMobile = unionUserConfig.getUserMobile(backendToken, token.getJSONObject("params").getString("accessToken"), token.getJSONObject("params").getString("openId"));
            if (userMobile == null || !userMobile.getString("resp").equals("00")) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, userMobile.getString("msg"));
            }
            // 解密，获取手机号
            String mobile = UnionUtils.getDecryptedValue(userMobile.getJSONObject("params").getString("mobile"), unionUserConfig.getRsaKey());
            Map<String, Object> other = new HashMap<>();
            other.put("unionId", token.getJSONObject("params").getString("openId"));
            other.put("unionUnionId", token.getJSONObject("params").getString("unionId"));
            return ResponseMsgUtil.success(userService.loginAndRegister(LoginPlatform.UNIONPAY, mobile, body.getLong("popularizeUserId"), other, request, response));

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

    @RequestMapping(value = "/out", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "退出登录")
    public ResponseData out(HttpServletRequest request, HttpServletResponse response) {
        try {
            HighUserModel userInfoModel = userCenter.getSessionModel(HighUserModel.class);
            if (userInfoModel == null) {
                log.error("CoresController --> outLogin() error!", "用户身份错误或已过期");
                throw ErrorHelp.genException(SysCode.System, ErrorCode.SEC_USER_EXPIRED, "");
            }
            userCenter.remove(request, response);
            return ResponseMsgUtil.success("退出登录成功");

        } catch (Exception e) {
            log.error("CoresController --> outLogin() error!", e);
            return ResponseMsgUtil.exception(e);
        }
    }

}

