package com.yfd.platform.system.controller;

import cn.hutool.cache.impl.CacheObj;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wf.captcha.base.Captcha;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.DatabaseConfigReader;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.config.TencentSmsProperties;
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.SysRole;
import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.service.ISysLogService;
import com.yfd.platform.system.service.ISysRoleService;
import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.system.service.impl.UserDetailsServiceImpl;
import com.yfd.platform.utils.FileUtil;
import com.yfd.platform.utils.RequestHolder;
import com.yfd.platform.utils.StringUtils;
import com.yfd.platform.utils.sm3.SM3Utils;
import com.yfd.platform.utils.sm4.SM4Utils;
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.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


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

    @Autowired
    private WebConfig webConfig;

    @Resource
    private IUserService userService;

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

    @Resource
    private ISysLogService sysLogService;

    @Resource
    private LoginProperties loginProperties;

    @Resource
    private TencentSmsProperties smsProperties;

    @Resource
    private ISysRoleService sysRoleService;

    @Resource
    UserDetailsServiceImpl userDetailsService;
    @Resource
    private DatabaseConfigReader databaseConfigReader;

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

        //用于开发测试，减少验证时间，正式使用应该改成true
        boolean hascode = true;
        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("图片验证码错误！");
            }
        }
        if (hascode && StrUtil.isNotBlank(user.getPhone())) {
            // 短信登录
            String phone = user.getPhone();
            if (!Validator.isMobile(phone)) {
                return ResponseResult.error("手机号不正确！");
            }
            String key = Constant.USER_LOGIN + phone;
            String verifyCode = webConfig.loginuserCache().get(key);
            if (StrUtil.isBlank(verifyCode)) {
                return ResponseResult.error("验证码不存在或已过期！");
            }
            if (StrUtil.isBlank(user.getCode()) || !user.getCode().equalsIgnoreCase(verifyCode)) {
                return ResponseResult.error("验证码错误！");
            }
        }

        //检查用户名是否存在
        boolean isok = userDetailsService.checkUsername(user.getUsername());
        if (!isok) {
            return ResponseResult.error("用户账号不存在！");
        }
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        String requestip = StringUtils.getIp(request);
        String brower = StringUtils.getBrowser(request);
        //用于开发测试，减少验证时间，正式使用应该改成true
        boolean checkpassword = true;
        if (checkpassword) {
            //检查用户登录IP是否是合法的（设置允许的）
            String loginip = StringUtils.getIp(request);
            boolean islegalip = userDetailsService.checkUserLoginIp(loginip, user.getUsername());
            if (islegalip == false) {
                return ResponseResult.error("用户登录IP不合法，请联系管理员！");
            }

            JSONObject checkinfo = userDetailsService.checkPassword(user.getUsername(), password, requestip, brower);
            if (!checkinfo.getBool("isok")) {
                //密码不正确,返回错误信息
                return ResponseResult.error(checkinfo.getStr("errorinfo"));
            }
        }
        //获取登录信息
        LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(user.getUsername());
        SysUser user1 = loginUser.getUser();
        Integer status = user1.getStatus();
        String userId = loginUser.getUser().getId();
//        String loginStr = webConfig.loginuserCache().get("login:" + userId);
//        if (StrUtil.isNotBlank(loginStr)) {
//            return ResponseResult.message("3", userId);
//        }
        if (status == 0) {
            return ResponseResult.error("用户已停用");
        }
        if (status == 2) {
            return ResponseResult.error("用户已锁定");
        }

        SysLog sysLog = new SysLog();
        sysLog.setUsercode(user.getUsername());
        sysLog.setUsername(loginUser.getUser().getNickname());
        sysLog.setRequestip(StringUtils.getIpAddr(request));
        sysLog.setBrowser(StringUtils.getBrowser(request));
        sysLog.setType("0");
        sysLog.setOpttype("登录(login)");
        sysLog.setModule("用户登录");
        String className = this.getClass().getName();
        String method =
                Thread.currentThread().getStackTrace()[1].getMethodName();
        sysLog.setMethod(className + "." + method + "()");
        sysLog.setDescription(loginUser.getUser().getNickname() + "登录系统！");
        sysLog.setLogtime(new Timestamp(System.currentTimeMillis()));
        sysLogService.save(sysLog);
        String content = "系统日志\t" +
                user.getUsername() + "\t" +
                loginUser.getUser().getNickname() + "\t" +
                "用户登录\t" +
                loginUser.getUser().getNickname() + "登录系统！\t" +
                className + "." + method + "()" + "\t" +
                StringUtils.getIpAddr(request) + "\t" +
                StringUtils.getBrowser(request) + "\t" +
                "登录(login)\t" +
                DateUtil.now() + "\t\n";
        FileUtil.appendUtf8String(content, new File(databaseConfigReader.getBackupPath() + "sysLog.txt"));
        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() + (30L * 60L * 1000L);//30分钟无操作退出
                //                long expireTime =
                //                        System.currentTimeMillis() + ( 30L * 24L * 60L * 60L * 1000L); //30天
                put("expire_time", expireTime);//个月过期
            }
        };

        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);
        webConfig.loginuserCache().put("expire_time:" + userId, map.get("expire_time").toString());
        Integer usertype = loginUser.getUser().getUsertype();
        if (usertype == 1) {// 非超级管理员
            List<String> roleId = userService.getRoleId(loginUser.getUser().getId());
            if (roleId == null || roleId.size() == 0) {
                return ResponseResult.error("您没有分配角色，不能登录系统");
            } else {
                List<SysRole> list = sysRoleService.list(new LambdaQueryWrapper<SysRole>().in(SysRole::getId, roleId));
                long count = list.stream().filter(l -> "2".equals(l.getLevel()) || "4".equals(l.getLevel())).count();
                if (count > 0) { //系统管理和安全审计
                    map.put("goto", "admin");
                } else {
                    long count1 = list.stream().filter(l -> "3".equals(l.getLevel())).count();
                    if (count1 > 0) { //具有业务操作员角
                        // 判断登录页面是否勾选管理后
                        String flag = user.getCustom3();
                        if ("1".equals(flag)) {
                            map.put("goto", "admin");
                        } else {
                            map.put("goto", "business");
                        }
                    }
                }
            }
        } else {
            String flag = user.getCustom3();
            if ("1".equals(flag)) {
                map.put("goto", "admin");
            } else {
                map.put("goto", "business");
            }
        }
        return ResponseResult.successData(map);
    }

    @PostMapping("/loginCode")
    @ApiOperation("发送登录验证码")
    @ResponseBody
    public ResponseResult loginCode(String phone) {
        if (StrUtil.isBlank(phone)) {
            return ResponseResult.error("请填写手机号");
        }
        if (!Validator.isMobile(phone)) {
            return ResponseResult.error("手机号格式不正确！");
        }
        //        String verifyCode = webConfig.loginuserCache().get(Constant.USER_LOGIN + phone);
        //        if (StrUtil.isNotBlank(verifyCode)) {
        //            return ResponseResult.error("验证码还在有效期内");
        //        }
        long codeL = System.nanoTime();
        String codeStr = Long.toString(codeL);
        String code = codeStr.substring(codeStr.length() - 8, codeStr.length() - 2);
        // 拼成唯一的key
        // 将手机验证码设置到缓存，五分钟失效
        webConfig.loginuserCache().put(Constant.USER_LOGIN + phone, code, 1000 * 60 * 5);
        String sessionContext = "登录验证码";
        String templateId = smsProperties.getTemplateIdMap().get("login");
        String[] templateParamSet = new String[1];
        templateParamSet[0] = code;
        phone = "+86" + phone;
        boolean ok = userService.sendVerCodeToPhone(phone, sessionContext, templateId, templateParamSet);
        if (ok) {
            return ResponseResult.success();
        }
        return ResponseResult.error();
    }

    @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];
        }

        // 将验证码放入缓存，设置失效时间为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
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication instanceof UsernamePasswordAuthenticationToken) {
            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.getIpAddr(request));
            sysLog.setBrowser(StringUtils.getBrowser(request));
            String className = this.getClass().getName();
            String method =
                    Thread.currentThread().getStackTrace()[1].getMethodName();
            sysLog.setMethod(className + "." + method + "()");
            sysLog.setType("0");
            sysLog.setOpttype("登出(logout)");
            sysLog.setModule("退出系统");
            sysLog.setDescription(loginuser.getUser().getNickname() + "注销退出系统！");
            sysLog.setLogtime(new Timestamp(System.currentTimeMillis()));
            sysLogService.save(sysLog);
            String content = "系统日志\t" +
                    loginuser.getUsername() + "\t" +
                    loginuser.getUser().getNickname() + "\t" +
                    "退出系统\t" +
                    loginuser.getUser().getNickname() + "注销退出系统！\t" +
                    className + "." + method + "()" + "\t" +
                    StringUtils.getIpAddr(request) + "\t" +
                    StringUtils.getBrowser(request) + "\t" +
                    "登出(logout)\t" +
                    DateUtil.now() + "\t\n";

            FileUtil.appendUtf8String(content, new File(databaseConfigReader.getBackupPath() + "sysLog.txt"));
        }


        return ResponseResult.success();
    }

    @GetMapping("/me")
    @ApiOperation("查询当前用户信息")
    @ResponseBody
    public ResponseResult getUserInfo() {
        ResponseResult responseResult = userService.getLoginUserInfo();
        if (responseResult == null) {
            return ResponseResult.error("当前用户没有权限");
        }
        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();
        }

    }

    @PostMapping("/kickOutUser")
    @ApiOperation("踢出用户")
    @ResponseBody
    public ResponseResult kickOutUser(String userId) {
        webConfig.loginuserCache().remove("login:" + userId);
        return ResponseResult.success();
    }


}
