package com.njcn.gather.user.user.controller;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.njcn.common.bean.CustomCacheUtil;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.constant.OperateType;
import com.njcn.common.pojo.constant.SecurityConstants;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.JwtUtil;
import com.njcn.common.utils.LogUtil;
import com.njcn.common.utils.RSAUtil;
import com.njcn.gather.user.pojo.constant.UserValidMessage;
import com.njcn.gather.user.pojo.enums.UserResponseEnum;
import com.njcn.gather.user.user.pojo.param.SysUserParam;
import com.njcn.gather.user.user.pojo.po.SysUser;
import com.njcn.gather.user.user.pojo.po.Token;
import com.njcn.gather.user.user.service.ISysUserService;
import com.njcn.web.controller.BaseController;
import com.njcn.web.utils.HttpResultUtil;
import com.njcn.web.utils.RequestUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.security.KeyPair;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;


@Slf4j
@RestController
@Api(tags = "登录-注销")
@RequestMapping("/admin")
@RequiredArgsConstructor
public class AuthController extends BaseController {

    private final ISysUserService sysUserService;
    private final CustomCacheUtil customCacheUtil;
    private KeyPair keyPair;


    @OperateInfo(info = LogEnum.SYSTEM_COMMON, operateType = OperateType.AUTHENTICATE)
    @PostMapping("/login")
    @ApiOperation("登录")
    public HttpResult<Object> login(@RequestBody SysUserParam.LoginParam param, HttpServletRequest request) {
        String methodDescribe = getMethodDescribe("login");
        LogUtil.njcnDebug(log, "{}，登录参数为：{}", methodDescribe, param);
        byte[] decode = Base64.getDecoder().decode(param.getUsername());
        String username = new String(decode);
        String password = null;

        try {
            password = RSAUtil.decrypt(param.getPassword(), keyPair.getPrivate());
        } catch (Exception e) {
            throw new BusinessException(UserResponseEnum.RSA_DECRYT_ERROR);
        }
        // 因不确定是否能登陆成功先将登陆名保存到request，一遍记录谁执行了登录操作
        request.setAttribute(SecurityConstants.AUTHENTICATE_USERNAME, username);
        SysUser user = sysUserService.getUserByLoginNameAndPassword(username, password);
        if (ObjectUtil.isNull(user)) {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, null, UserValidMessage.LOGIN_FAILED);
        } else {
            String accessToken = JwtUtil.getAccessToken(user.getId(), user.getLoginName());
            String refreshToken = JwtUtil.getRefreshToken(accessToken);
            Token token = new Token();
            token.setAccessToken(accessToken);
            token.setRefreshToken(refreshToken);

            Map<String, Object> map = new HashMap<>();
            map.put("name", user.getName());
            map.put("id", user.getId());
            map.put("loginName", user.getLoginName());

            token.setUserInfo(map);

            customCacheUtil.putWithExpireTime(accessToken, JSON.toJSONString(user), DateUnit.DAY.getMillis() * Integer.MAX_VALUE);
            sysUserService.updateLoginTime(user.getId());
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, token, methodDescribe);
        }
    }

    @OperateInfo(info = LogEnum.SYSTEM_SERIOUS, operateType = OperateType.LOGOUT)
    @ApiOperation("注销登录")
    @PostMapping("/logout")
    public HttpResult<Object> logout() {
        String methodDescribe = getMethodDescribe("logout");
        LogUtil.njcnDebug(log, "{}，注销登录", methodDescribe);
        String accessToken = RequestUtil.getAccessToken();
        if (StrUtil.isNotBlank(accessToken)) {
            customCacheUtil.remove(accessToken);

            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
        }
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, null, methodDescribe);
    }

    @OperateInfo(info = LogEnum.SYSTEM_COMMON)
    @ApiOperation("刷新accessToken")
    @GetMapping("/refreshToken")
    public HttpResult<Object> refreshToken(HttpServletRequest request) {
        String methodDescribe = getMethodDescribe("refreshToken");
        LogUtil.njcnDebug(log, "{}，刷新token", methodDescribe);
        String accessToken = RequestUtil.getAccessToken();

        Token token = new Token();
        if (StrUtil.isNotBlank(accessToken)) {
            Map<String, Object> map = JwtUtil.parseToken(accessToken);
            String userId = (String) map.get(SecurityConstants.USER_ID);
            SysUser user = sysUserService.getById(userId);
            String accessTokenNew = JwtUtil.getAccessToken(userId, user.getLoginName());
            request.setAttribute(SecurityConstants.AUTHENTICATE_USERNAME, user.getLoginName());
//            String refreshTokenNew = JwtUtil.getRefreshToken(accessTokenNew);

            token.setAccessToken(accessTokenNew);
            token.setRefreshToken(accessToken);

            customCacheUtil.putWithExpireTime(accessTokenNew, JSON.toJSONString(user), DateUnit.DAY.getMillis() * Integer.MAX_VALUE);
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, token, methodDescribe);
        } else {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, null, methodDescribe);
        }
    }

    @OperateInfo(info = LogEnum.SYSTEM_COMMON)
    @ApiOperation("获取RSA公钥")
    @GetMapping("/getPublicKey")
    public HttpResult<String> publicKey(@RequestParam("username") String username, HttpServletRequest request) throws Exception {
        String methodDescribe = getMethodDescribe("publicKey");
        LogUtil.njcnDebug(log, "{}，获取RSA公钥", methodDescribe);
        // 因不确定是否能登陆成功先将登陆名保存到request，一遍记录谁执行了登录操作
        request.setAttribute(SecurityConstants.AUTHENTICATE_USERNAME, username);
        keyPair = RSAUtil.generateKeyPair();
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, RSAUtil.publicKeyToString(keyPair.getPublic()), methodDescribe);
    }
}
