package com.yfd.platform.system.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.wf.captcha.base.Captcha;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.config.WebConfig;
import com.yfd.platform.config.bean.LoginCodeEnum;
import com.yfd.platform.config.bean.LoginProperties;
import com.yfd.platform.constant.Constant;
import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.system.domain.SysLog;
import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.service.ISysLogService;
import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.utils.RequestHolder;
import com.yfd.platform.utils.RsaUtils;
import com.yfd.platform.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;

/**
 * @author LiMengNan
 */
@RestController
@RequestMapping("/user")
@Api(value = "LoginController", tags = "用户登录")
public class LoginController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private WebConfig webConfig;

    @Resource
    private IUserService userService;

    @Value("${rsa.private_key}")
    private String privateKey;

    @Resource
    private ISysLogService sysLogService;

    @Resource
    private LoginProperties loginProperties;

    @PostMapping("/login")
    @ApiOperation("登录用户")
    @ResponseBody
    public ResponseResult login(SysUser user) throws Exception {
        // 密码解密
        String password = RsaUtils.decryptByPrivateKey(privateKey,
                user.getPassword());

        // 是否需要验证码不需要改成false
        boolean hascode = false;
        if (hascode) {
            // 查询验证码
            String code = webConfig.loginuserCache().get(user.getUuid());
            // 清除验证码
            webConfig.loginuserCache().remove(user.getUuid());
            if (StrUtil.isBlank(code)) {
                return ResponseResult.error("验证码不存在或已过期");
            }
            if (StrUtil.isBlank(user.getCode()) || !user.getCode().equalsIgnoreCase(code)) {
                return ResponseResult.error("验证码错误");
            }
        }
        //如果认证通过了，使用userId生成token token存入ResponseResult返回
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(user.getUsername(),
                        password);
        Authentication authenticate =
                authenticationManager.authenticate(authenticationToken);
        if (ObjectUtil.isNull(authenticate)) {
            return ResponseResult.unlogin();
        }
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        Integer status = loginUser.getUser().getStatus();
        if ("0".equals(status.toString())) {
            return ResponseResult.error("账号已停用");
        }
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        SysLog sysLog = new SysLog();
        sysLog.setUsercode(user.getUsername());
        sysLog.setUsername(loginUser.getUser().getNickname());
        sysLog.setRequestip(StringUtils.getIp(request));
        sysLog.setBrowser(StringUtils.getBrowser(request));
        sysLog.setOpttype("登录(login)");
        sysLog.setModule("用户登录");
        String className = this.getClass().getName();
        String method =
                Thread.currentThread().getStackTrace()[1].getMethodName();
        sysLog.setMethod(className + "." + method + "()");
        //sysLog.setParams(user.toString());
        sysLog.setDescription(loginUser.getUser().getNickname() + "登录系统！");
        sysLog.setLogtime(new Timestamp(System.currentTimeMillis()));
        sysLogService.save(sysLog);
        String userId = loginUser.getUser().getId();
        Map<String, Object> map = new HashMap<String, Object>(10) {
            private static final long serialVersionUID = 1L;

            {
                put("userid", userId);
                put("username", loginUser.getUsername());
                long expireTime =
                        System.currentTimeMillis() + (long) (30L * 24L * 60L * 60L * 1000L);
                put("expire_time", expireTime);//1个月过期
            }
        };

        String token = JWTUtil.createToken(map, "12345678".getBytes());
        map.put("token", token);
        //把完整的用户信息存入到HuTool缓存中，userId作为key
        String jsonStr = JSONUtil.toJsonStr(loginUser);
        webConfig.loginuserCache().put("login:" + userId, jsonStr);
        return ResponseResult.successData(map);
    }

    @ApiOperation("获取验证码")
    @GetMapping(value = "/code")
    public ResponseResult getCode() {
        // 获取运算的结果
        Captcha captcha = loginProperties.getCaptcha();
        String uuid = Constant.CODE_KEY + IdUtil.simpleUUID();
        //当验证码类型为 arithmetic时且长度 >= 2 时，captcha.text()的结果有几率为浮点型
        String captchaValue = captcha.text();
        if (captcha.getCharType() - 1 == LoginCodeEnum.arithmetic.ordinal() && captchaValue.contains(".")) {
            captchaValue = captchaValue.split("\\.")[0];
        }
        // 保存
        //redisUtils.set(uuid, captchaValue, loginProperties.getLoginCode()
        // .getExpiration(), TimeUnit.MINUTES);
        // 将验证码放入缓存，设置失效时间为60秒
        webConfig.loginuserCache().put(uuid, captchaValue,
                Constant.CODE_EXPIRATION_TIME);
        // 验证码信息
        Map<String, Object> imgResult = new HashMap<String, Object>(2) {{
            put("img", captcha.toBase64());
            put("uuid", uuid);
        }};
        return ResponseResult.successData(imgResult);
    }

    @PostMapping("/logout")
    @ApiOperation("退出登录")
    @ResponseBody
    public ResponseResult logout() {
        //获取SecurityContextHolder中的用户id
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginuser = (LoginUser) authentication.getPrincipal();
        String userId = loginuser.getUser().getId();
        //删除redis中的登陆用户信息
        webConfig.loginuserCache().remove("login:" + userId);
        //记录退出日志
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        SysLog sysLog = new SysLog();
        sysLog.setUsercode(loginuser.getUsername());
        sysLog.setUsername(loginuser.getUser().getNickname());
        sysLog.setRequestip(StringUtils.getIp(request));
        sysLog.setBrowser(StringUtils.getBrowser(request));
        sysLog.setOpttype("其他(other)");
        sysLog.setModule("注销退出");
        sysLog.setDescription("注销退出系统！");
        sysLog.setLogtime(new Timestamp(System.currentTimeMillis()));
        sysLogService.save(sysLog);
        return ResponseResult.success();
    }

    @Log(module = "用户登录", value = "更改用户密码")
    @GetMapping("/updatePassword")
    @ApiOperation("更改用户密码")
    @ResponseBody
    public ResponseResult updatePassword(SysUser user) throws Exception {
        // 密码解密
        String password = RsaUtils.decryptByPrivateKey(privateKey,
                user.getPassword());
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String cryptPassword = passwordEncoder.encode(password);
        UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("password", cryptPassword);
        updateWrapper.eq("id", user.getId());
        userService.update(updateWrapper);
        return ResponseResult.success();
    }

    @GetMapping("/me")
    @ApiOperation("查询当前用户信息")
    @ResponseBody
    public ResponseResult getUserInfo() {
        ResponseResult responseResult = userService.getLoginUserInfo();
        return ResponseResult.successData(responseResult);
    }

    @Log(module = "用户登录", value = "修改个人信息")
    @PostMapping("/updatePersonalInfo")
    @ApiOperation("修改个人信息")
    @ResponseBody
    public ResponseResult updateUser(@RequestBody SysUser user) {
        if (StrUtil.isEmpty(user.getId())) {
            return ResponseResult.error("没有用户ID");
        }
        //填写 当前用户名称
        user.setLastmodifier(userService.getUsername());
        //填写 当前日期
        user.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
        boolean ok = userService.updateById(user);
        if (ok) {
            return ResponseResult.success();
        } else {
            return ResponseResult.error();
        }

    }

}
