/*
 * Copyright (c) 2018-2999 广州亚米信息科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.api.controller;


import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Maps;
import com.yami.shop.bean.app.param.CheckRegisterSmsParam;
import com.yami.shop.bean.app.param.SendSmsParam;
import com.yami.shop.bean.app.param.UserRegisterParam;
import com.yami.shop.bean.enums.SmsType;
import com.yami.shop.bean.model.User;
import com.yami.shop.common.exception.GlobalException;
import com.yami.shop.common.util.IPHelper;
import com.yami.shop.common.util.PrincipalUtil;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.config.WxConfig;
import com.yami.shop.security.api.model.YamiUser;
import com.yami.shop.security.api.service.YamiUserDetailsService;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.security.comment.handler.LoginAuthSuccessHandler;
import com.yami.shop.security.comment.model.AppConnect;
import com.yami.shop.security.comment.service.AppConnectService;
import com.yami.shop.security.comment.token.AuthenticationToken;
import com.yami.shop.service.SmsLogService;
import com.yami.shop.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Date;
import java.util.Objects;


/**
 * 用户信息
 *
 * @author LGH
 */
@RestController
@RequestMapping("/user")
@Api(tags = "用户注册相关接口")
@AllArgsConstructor
public class UserRegisterController {

    private final UserService userService;

    private final SmsLogService smsLogService;

    private final AppConnectService appConnectService;

    private final LoginAuthSuccessHandler loginAuthSuccessHandler;

    private final WxConfig wxConfig;

    private final YamiUserDetailsService yamiUserDetailsService;

    private final PasswordEncoder passwordEncoder;


    public static final String CHECK_REGISTER_SMS_FLAG = "checkRegisterSmsFlag";

    public static final String CHECK_UPDATE_PWD_SMS_FLAG = "updatePwdSmsFlag";

    @PutMapping("/sendRegisterSms")
    @ApiOperation(value = "发送注册验证码", notes = "发送注册验证码")
    public ResponseEntity<Void> register(@Valid @RequestBody SendSmsParam sendSmsParam) {
        if (userService.count(new LambdaQueryWrapper<User>().eq(User::getUserMobile, sendSmsParam.getMobile())) > 0) {
            throw new GlobalException("该手机号已注册，无法重新注册");
        }
        // 每个手机号每分钟只能发十个注册的验证码，免得接口被利用
        smsLogService.sendSms(SmsType.REGISTER, sendSmsParam.getMobile(), sendSmsParam.getMobile(), Maps.newHashMap());
        return ResponseEntity.ok().build();
    }

    @PutMapping("/checkRegisterSms")
    @ApiOperation(value = "校验验证码", notes = "校验验证码返回校验成功的标识")
    public ResponseEntity<String> register(@Valid @RequestBody CheckRegisterSmsParam checkRegisterSmsParam) {
        // 每个ip每分钟只能发十个注册的验证码，免得接口被利用
        if (!smsLogService.checkValidCode(checkRegisterSmsParam.getMobile(), checkRegisterSmsParam.getValidCode(), SmsType.REGISTER)) {
            throw new GlobalException("验证码有误或已过期");
        }
        String checkRegisterSmsFlag = IdUtil.simpleUUID();
        RedisUtil.set(CHECK_REGISTER_SMS_FLAG + checkRegisterSmsFlag, checkRegisterSmsParam.getMobile(), 600);
        return ResponseEntity.ok(checkRegisterSmsFlag);
    }

    @PutMapping("/sendBindSms")
    @ApiOperation(value = "发送绑定验证码", notes = "发送绑定验证码")
    public ResponseEntity<Void> bindSms(@Valid @RequestBody SendSmsParam sendSmsParam) {
        // 每个手机号每分钟只能发十个注册的验证码，免得接口被利用
        smsLogService.sendSms(SmsType.VALID, sendSmsParam.getMobile(), sendSmsParam.getMobile(), Maps.newHashMap());
        return ResponseEntity.ok().build();
    }

    @PutMapping("/registerOrBindUser")
    @ApiOperation(value = "注册或绑定手机号", notes = "用户注册或绑定手机号接口")
    public ResponseEntity<Void> register(HttpServletRequest request, HttpServletResponse response, @Valid @RequestBody UserRegisterParam userRegisterParam) {

        String mobile = userRegisterParam.getMobile();
        AppConnect appConnect = null;
        User user = null;
        String bizUserId = null;


        // 正在进行注册，通过验证码校验
        if (Objects.equals(userRegisterParam.getRegisterOrBind(), 1)) {

            // 看看有没有校验验证码成功的标识
            userService.validate(userRegisterParam, CHECK_REGISTER_SMS_FLAG + userRegisterParam.getCheckRegisterSmsFlag());
            // 正在进行申请注册
            if (userService.count(new LambdaQueryWrapper<User>().eq(User::getUserMobile, userRegisterParam.getMobile())) > 0) {
                throw new GlobalException("手机号已存在，无法注册");
            }
        }
        // 小程序注册/绑定手机号
        else {
            // 检查用户是否已经认证，只有在认证状态下才获取用户信息
                YamiUser yamiUser = SecurityUtils.getUser();
                appConnect = appConnectService.getByBizUserId(yamiUser.getBizUserId(), yamiUser.getAppType());
                bizUserId = yamiUser.getBizUserId();
                // 通过微信手机号校验
                if (Objects.equals(2, userRegisterParam.getValidateType())) {
                    try {
                        WxMaPhoneNumberInfo wxMaPhoneNumberInfo = wxConfig.getWxMaService().getUserService().getPhoneNoInfo(yamiUser.getSessionKey(), userRegisterParam.getEncryptedData(), userRegisterParam.getIvStr());
                        mobile = wxMaPhoneNumberInfo.getPhoneNumber();

                    } catch (Exception e) {
                        throw new GlobalException("授权失败，请重新授权");
                    }
                    if (StrUtil.isBlank(mobile)) {
                        throw new GlobalException("无法获取用户手机号信息");
                    }
                    user = yamiUserDetailsService.loadUserByMobileOrUserName(mobile, 0);
                }
                // 通过账号密码校验
                else if (Objects.equals(3, userRegisterParam.getValidateType())) {
                    user = yamiUserDetailsService.loadUserByMobileOrUserName(mobile, 0);
                    if (user == null) {
                        throw new GlobalException("账号或密码不正确");
                    }
                    String encodedPassword = user.getLoginPassword();
                    String rawPassword = userRegisterParam.getPassword();
                    // 密码不正确
                    if (StrUtil.isBlank(encodedPassword) || !passwordEncoder.matches(rawPassword, encodedPassword)) {
                        throw new GlobalException("账号或密码不正确");
                    }
                }
                // 通过验证码校验
                else {
                    if (!smsLogService.checkValidCode(userRegisterParam.getMobile(), userRegisterParam.getValidCode(), SmsType.VALID)) {
                        throw new GlobalException("验证码有误或已过期");
                    }
                }
        }

        Date now = new Date();
        if (user == null && StrUtil.isNotBlank(mobile)) {
            user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, mobile).eq(User::getChannelId, userRegisterParam.getChannelId()));
        }

        // 新建用户
        if (user == null) {
            user = new User();
            if (StrUtil.isBlank(userRegisterParam.getUserName())) {
                userRegisterParam.setUserName(mobile);
            }

            // 如果有用户名,就判断用户名格式是否正确
            if (!PrincipalUtil.isUserName(userRegisterParam.getUserName())) {
                throw new GlobalException("用户名应由4-16位数字字母下划线组成");
            }

            user.setModifyTime(now);
            user.setUserRegtime(now);
            user.setUserRegip(IPHelper.getIpAddr());
            user.setStatus(1);
			user.setChannelId(userRegisterParam.getChannelId());
            user.setPic(userRegisterParam.getImg());
            user.setUserMobile(mobile);
            user.setUserName(userRegisterParam.getUserName());
            if (StrUtil.isNotBlank(userRegisterParam.getPassword())) {
                user.setLoginPassword(passwordEncoder.encode(userRegisterParam.getPassword()));
            }
            // 用户名就是默认的昵称
            user.setNickName(StrUtil.isBlank(userRegisterParam.getNickName()) ? userRegisterParam.getUserName() : userRegisterParam.getNickName());
        }


        appConnectService.registerOrBindUser(user, appConnect, userRegisterParam.getAppType());


        //进行授权登录
        UserDetails userDetails = yamiUserDetailsService.getYamiUser(userRegisterParam.getAppType(), user, bizUserId);
        AuthenticationToken authenticationToken = new AuthenticationToken();
        authenticationToken.setPrincipal(user.getUserMobile());
        authenticationToken.setCredentials(user.getLoginPassword());
        authenticationToken.setPrincipal(userDetails.getUsername());
        authenticationToken.setDetails(userDetails);
        authenticationToken.setAuthenticated(true);
        loginAuthSuccessHandler.onAuthenticationSuccess(request, response, authenticationToken);

        return ResponseEntity.ok().build();
    }


    @PutMapping("/checkUpdatePwdSms")
    @ApiOperation(value = "修改密码校验验证码", notes = "校验验证码返回校验成功的标识")
    public ResponseEntity<String> checkUpdatePwdSms(@Valid @RequestBody CheckRegisterSmsParam checkRegisterSmsParam) {
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, checkRegisterSmsParam.getMobile()));
        if (user == null) {
            throw new GlobalException("无法获取用户信息");
        }
        if (!smsLogService.checkValidCode(user.getUserMobile(), checkRegisterSmsParam.getValidCode(), SmsType.UPDATE_PASSWORD)) {
            throw new GlobalException("验证码有误或已过期");
        }
        String checkRegisterSmsFlag = IdUtil.simpleUUID();
        RedisUtil.set(CHECK_UPDATE_PWD_SMS_FLAG + checkRegisterSmsFlag, checkRegisterSmsParam.getMobile(), 600);
        return ResponseEntity.ok(checkRegisterSmsFlag);
    }

    @PutMapping("/updatePwd")
    @ApiOperation(value = "修改密码", notes = "修改密码")
    public ResponseEntity<Void> updatePwd(@Valid @RequestBody UserRegisterParam userRegisterParam) {
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, userRegisterParam.getMobile()));
        if (user == null) {
            throw new GlobalException("无法获取用户信息");
        }
        // 看看有没有校验验证码成功的标识
        userService.validate(userRegisterParam, CHECK_UPDATE_PWD_SMS_FLAG + userRegisterParam.getCheckRegisterSmsFlag());
        if (StrUtil.isBlank(userRegisterParam.getPassword())) {
            throw new GlobalException("新密码不能为空");
        }
        if (StrUtil.equals(passwordEncoder.encode(userRegisterParam.getPassword()), user.getLoginPassword())) {
            throw new GlobalException("新密码不能与原密码相同!");
        }
        user.setModifyTime(new Date());
        user.setLoginPassword(passwordEncoder.encode(userRegisterParam.getPassword()));
        userService.updateById(user);
        return ResponseEntity.ok().build();
    }
}
