package com.storlead.system.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.storlead.framework.auth.jwt.JwtUtil;
import com.storlead.framework.auth.vo.LoginUser;
import com.storlead.framework.auth.vo.MenuPermis;
import com.storlead.framework.common.constant.CommonConstant;
import com.storlead.framework.common.constant.DefContants;
import com.storlead.framework.common.constant.RedisKeySaltConstant;
import com.storlead.framework.common.ecode.BCryptPasswordEncoder;
import com.storlead.framework.common.result.Result;
import com.storlead.framework.common.util.ConvertUtils;
import com.storlead.framework.common.util.MD5Util;
import com.storlead.framework.common.util.RsaUtils;
import com.storlead.framework.common.util.sso.CryptoZipUtil;
import com.storlead.framework.common.util.sso.HttpSecurityCheckUtil;
import com.storlead.framework.redis.RedisService;
import com.storlead.framework.util.LoginUserUtil;
import com.storlead.sms.pojo.entity.SmsLogEntity;
import com.storlead.sms.spi.SmsCaptchaScene;
import com.storlead.sms.spi.SmsCaptchaService;
import com.storlead.sms.spi.SmsLogService;
import com.storlead.system.pojo.entity.MenuEntity;
import com.storlead.system.service.IMenuService;
import com.storlead.system.service.IUserRoleService;
import com.storlead.system.util.SystemConfigItemCacheUtil;
import com.storlead.user.pojo.dto.UserLoginDTO;
import com.storlead.user.pojo.entity.DeptEntity;
import com.storlead.user.pojo.entity.JobEntity;
import com.storlead.user.pojo.entity.UserEntity;
import com.storlead.user.pojo.entity.UserForm;
import com.storlead.user.service.IDepartService;
import com.storlead.user.service.IJobService;
import com.storlead.user.service.IUserService;
import com.storlead.wecom.service.CorpWeChatService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @program: sp-sales
 * @description:
 * @author: chenkq
 * @create: 2022-07-15 10:11
 */
@RestController
@RequestMapping("/sys/auth")
@Api(tags="平台中心 - 系统: 认证接口")
@Slf4j
public class LoginApiController {

    @Resource
    private IUserService sysUserService;

    @Resource
    private RedisService redisService;

    @Resource
    private SmsLogService smsLogService;

    @Resource
    private SmsCaptchaService smsCaptchaService;

    @Resource
    private IDepartService departService;

    @Resource
    private IMenuService menuService;

    @Value("${environment}")
    private  String environment;

    @Resource
    private IUserRoleService userRoleService;

    @Resource
    private IJobService jobService;

    @Resource
    private CorpWeChatService corpWeChatService;

    @PostMapping(value = "/redirect")
    @ResponseBody
    public Object redirect(HttpServletRequest request, HttpServletResponse response)  throws IOException {
        response.sendRedirect("http://www.baidu.com");
        return Result.result("");
    }

    @PostMapping(value = "/login")
    @ApiOperation(value = "用户登录接口", notes = "用户登录接口")
    public Result login(@RequestBody UserLoginDTO loginDTO) {

        if (Objects.isNull(loginDTO)) {
            return Result.error("参数错误");
        }
        UserEntity userInfo;
        JSONObject obj = new JSONObject();
        if (StrUtil.isNotBlank(loginDTO.getWxCode())) {
            String code = corpWeChatService.login(loginDTO.getWxCode());
            userInfo = sysUserService.getOne(new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getXworkUserId,code));
        } else if (StrUtil.isNotBlank(loginDTO.getSmsCode())) {
            String mobile = StrUtil.trimToEmpty(loginDTO.getAccount());
            String smsCode = StrUtil.trimToEmpty(loginDTO.getSmsCode());
            if (StrUtil.isBlank(mobile)) {
                return Result.error("请输入手机号");
            }
            if (StrUtil.isBlank(smsCode)) {
                return Result.error("请输入验证码");
            }
            Result<?> vr = smsCaptchaService.verifyCaptcha(mobile, smsCode, SmsCaptchaScene.LOGIN, true);
            if (!vr.isSuccess()) {
                return Result.error(vr.getCode(), vr.getMessage());
            }
            userInfo = sysUserService.getOne(new LambdaQueryWrapper<UserEntity>()
                    .eq(UserEntity::getMobile, mobile)
                    .eq(UserEntity::getIsDelete, CommonConstant.DEL_FLAG_0));
            if (userInfo == null) {
                return Result.error("该手机号未绑定用户或账号已删除");
            }
        } else {
            if (StrUtil.isBlank(loginDTO.getAccount()) || StrUtil.isBlank(loginDTO.getPassword())) {
                return Result.error("用户名或密码为空");
            }
            userInfo = sysUserService.getOne(new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getMobile,loginDTO.getAccount()).eq(UserEntity::getIsDelete, CommonConstant.DEL_FLAG_0));
            if (Objects.isNull(userInfo)) {
                return Result.error("账号不存在");
            }

            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            String password = "";
            if((!environment.equals("prod") && !loginDTO.getPassword().equals("qq123456")) || environment.equals("prod")){
                try {
                    password = RsaUtils.decryptByPrivateKey(RsaUtils.PRIVATE_KEY, loginDTO.getPassword());
                }catch (Exception e) {
                    return Result.error("用户名或密码错误");
                }
            }
            if(environment.equals("prod") || (environment.equals("test")
                    && !loginDTO.getPassword().equals("qq123456") &&
                    !password.equals("qq123456"))) {
                if (!bCryptPasswordEncoder.matches(password, userInfo.getPassword())) {
                    return Result.error("用户名或密码错误");
                }
            }
            String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z\\W]{8,}$";
            String defaultPassWord = SystemConfigItemCacheUtil.getDefaultPassWord();

            if(password !=null && (!password.matches(regex) || password.equals(defaultPassWord))){
                obj.put("status",1);
            }else {
                obj.put("status",2);
            }

        }

        if (Objects.isNull(userInfo)) {
            return Result.error("登录失败,未获取到用户信息");
        }

        if (!userInfo.getEnabled()) {
            return Result.error("该账号用户暂无登录权限");
        }

        Integer possessMenuCount = menuService.checkUserMenuAccess(userInfo.getId());
        if (possessMenuCount == 0) {
            return Result.error("暂未获取到菜单权限,请联系管理员分配权限!");
        }

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(userInfo,loginUser);

        if (Objects.nonNull(userInfo.getJobId())) {
            JobEntity job = jobService.getById(userInfo.getJobId());
            if (Objects.nonNull(job)) {
                loginUser.setJobName(job.getName());
            }
        }

        loginUser.setRoleIds(userRoleService.selectUserRoleByUserId(userInfo.getId()));
        if (Objects.nonNull(userInfo.getDeptId())) {
            DeptEntity dept = departService.getById(userInfo.getDeptId());
            if (Objects.nonNull(dept)) {
                loginUser.setDeptName(dept.getName());
                loginUser.setDeptJobDes(dept.getDeptJobDes());
            }
        }

        //用户登录信息
        String jwtToken = JwtUtil.createJWT(JSONObject.toJSONString(loginUser),loginUser.getMobile());
        String token = SecureUtil.md5(jwtToken);

        String json = JSONObject.toJSONString(loginUser);
        redisService.setCacheObject(token, json, 60 * 60 * 24L * 7, TimeUnit.SECONDS);

        Map<String, String> apiMap = new HashMap();
        redisService.setCacheObject(RedisKeySaltConstant.API_CODE_REDIS + loginUser.getMobile(), apiMap);

        obj.put("token", token);
        return Result.result(obj);
    }

    @RequestMapping(value = "/ticket_login", method = RequestMethod.POST)
    @ApiOperation(value = "授权登录", notes = "授权登录")
    public Result ticketLogin(String ticket) {

        //解析加密
        if (StrUtil.isBlank(ticket)) {
            return Result.error("非法进入!");
        }
        JSONObject obj = new JSONObject();
        // 解密
        Map<String, String> argMap = CryptoZipUtil.decryptParams(ticket, CryptoZipUtil.SALT_KEY);
        argMap.put("appSecret","K7C2R5WJYfN6V9XbZqH4A8eLTMsPDmU3");

        // 解析参数
        String checkSign = MD5Util.MD5Encode(HttpSecurityCheckUtil.makeSign(argMap),"UTF-8").toLowerCase();
        String sign = argMap.get("sign").toString();
        if (!checkSign.equals(sign) || StrUtil.isBlank(checkSign)) {
            return Result.error("非法进入!");
        }
        long dt = Long.parseLong(argMap.get("dt"));
        long currentTime = (System.currentTimeMillis() /1000) % HttpSecurityCheckUtil.divisor;
        long difference = Math.abs(currentTime - dt);
        if (difference > 30) {
            return Result.error("连接已失效,请重新进入!");
        }
        String redirect = argMap.get("redirect").toString();
        if (StrUtil.isBlank(redirect)) {
            return Result.error("参数错误!");
        }
        obj.put("redirect",redirect);
        String token = argMap.get("token").toString();
        if (StrUtil.isNotBlank(token)) {
            Object info = redisService.getCacheObject(token);
            if (Objects.nonNull(info)) {
                obj.put("token",token);
                return Result.result(obj);
            }
        }
        String account = argMap.get("account").toString();
        if (StrUtil.isBlank(account)) {
            return Result.error("参数错误!");
        }
        UserEntity userInfo = sysUserService.getOne(new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getMobile,account));
        if (Objects.isNull(userInfo)) {
            return Result.error("授权失败,未找到用户信息!");
        }

        if (!userInfo.getEnabled()) {
            return Result.error("授权失败,无权限访问!");
        }

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(userInfo,loginUser);

        if (Objects.nonNull(userInfo.getJobId())) {
            JobEntity job = jobService.getById(userInfo.getJobId());
            if (Objects.nonNull(job)) {
                loginUser.setJobName(job.getName());
            }
        }

        loginUser.setRoleIds(userRoleService.selectUserRoleByUserId(userInfo.getId()));
        if (Objects.nonNull(userInfo.getDeptId())) {
            DeptEntity dept = departService.getById(userInfo.getDeptId());
            if (Objects.nonNull(dept)) {
                loginUser.setDeptName(dept.getName());
                loginUser.setDeptJobDes(dept.getDeptJobDes());
            }
        }

        //用户登录信息
        String jwtToken = JwtUtil.createJWT(JSONObject.toJSONString(loginUser),loginUser.getMobile());
        token = SecureUtil.md5(jwtToken);

        String json = JSONObject.toJSONString(loginUser);
        redisService.setCacheObject(token, json, 60 * 60 * 24L * 7, TimeUnit.SECONDS);

        Map<String, String> apiMap = new HashMap();
        redisService.setCacheObject(RedisKeySaltConstant.API_CODE_REDIS + loginUser.getMobile(), apiMap);

        obj.put("token", token);
        return Result.result(obj);
    }

    @ApiOperation("修改密码")
    @PostMapping("/modifyPass")
    public Object updateUserPass(@RequestBody @Validated UserForm param) {
        return sysUserService.updateUserPass(param);
    }


    /**
     * 退出登录
     * @param request
     * @param
     * @return
     */
    @PostMapping(value = "/logout")
    @ApiOperation(value = "用户退出登录接口", notes = "用户退出登录接口")
    public Result<Object> logout(HttpServletRequest request) {
        //用户退出逻辑
        String token = request.getHeader(DefContants.ACCESS_TOKEN);
        if(ConvertUtils.isEmpty(token)) {
            return Result.error("退出登录失败！");
        }
        Boolean del = redisService.deleteObject(token);
        if (del) {
            return Result.result("退出登录成功！");
        } else {
            Object obj = redisService.getCacheObject(token);
            if (obj == null) {
                return Result.error("退出登录成功！");
            }
            return Result.error("退出登录失败！");
        }
    }


    /**
     * 用户信息
     *
     * @param request
     * @return
     */
    @PostMapping("/getUserBaseInfo")
    @ApiOperation(value = "根据token获取用户基本信息", notes = "根据token获取用户基本信息(header中传token)")
    public Result<JSONObject> getUserBaseInfo(HttpServletRequest request) {

        LoginUser loginUser =  LoginUserUtil.getLoginUser();
        // 生成token
        Result<JSONObject> result = new Result<JSONObject>();
        //用户退出逻辑
        String token = request.getHeader(DefContants.ACCESS_TOKEN);
        UserEntity sysUser = sysUserService.getUserByName(loginUser.getUserName());
        // 获取用户部门信息
        JSONObject obj = new JSONObject();
        DeptEntity dept = departService.getById(sysUser.getDeptId());
        obj.put("dept", dept);
        obj.put("userInfo", sysUser);
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

    @RequestMapping(value = "/external_login", method = RequestMethod.POST)
    @ApiOperation(value = "外部用户登录接口", notes = "外部用户登录接口")
    public Result externalLogin(@RequestBody UserLoginDTO loginDTO) {

        if (Objects.isNull(loginDTO)) {
            return Result.error("参数错误");
        }
        UserEntity userInfo;
        JSONObject obj = new JSONObject();

        if (StrUtil.isBlank(loginDTO.getAccount()) || StrUtil.isBlank(loginDTO.getPassword())) {
            return Result.error("用户名或密码为空");
        }
        userInfo = sysUserService.getOne(new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getMobile,loginDTO.getAccount()));
        if (Objects.isNull(userInfo)) {
            return Result.error("账号不存在");
        }

        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String password = "";
        if((!environment.equals("prod") && !loginDTO.getPassword().equals("qq123456")) || environment.equals("prod")){
            try {
                password = RsaUtils.decryptByPrivateKey(RsaUtils.PRIVATE_KEY, loginDTO.getPassword());
            }catch (Exception e) {
                return Result.error("用户名或密码错误");
            }
        }
        if(environment.equals("prod") || (environment.equals("test")
                && !loginDTO.getPassword().equals("qq123456") &&
                !password.equals("qq123456"))) {
            if (!bCryptPasswordEncoder.matches(password, userInfo.getPassword())) {
                return Result.error("用户名或密码错误");
            }
        }
        String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z\\W]{8,}$";
        String defaultPassWord = SystemConfigItemCacheUtil.getDefaultPassWord();

        if(password !=null && (!password.matches(regex) || password.equals(defaultPassWord))){
            obj.put("status",1);
        }else {
            obj.put("status",2);
        }

        if (Objects.isNull(userInfo)) {
            return Result.error("登录失败,未获取到用户信息");
        }
        if (!Integer.valueOf(9).equals(userInfo.getExternalUserType())) {
            return Result.error("该账号暂无登录该系统的权限");
        }

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(userInfo,loginUser);

        //用户登录信息
        String jwtToken = JwtUtil.createJWT(JSONObject.toJSONString(loginUser),loginUser.getMobile());
        String token = SecureUtil.md5(jwtToken);

        String json = JSONObject.toJSONString(loginUser);
        redisService.setCacheObject(token, json, 60 * 60 * 24L * 7, TimeUnit.SECONDS);

        Map<String, String> apiMap = new HashMap();
        redisService.setCacheObject(RedisKeySaltConstant.API_CODE_REDIS + loginUser.getMobile(), apiMap);

        obj.put("token", token);
        return Result.result(obj);
    }

    @ApiOperation("获取当前用户信息")
    @PostMapping("/getCurrentUserInfo")
    public Object getCurrentUserInfo() {
        LoginUser loginUser = LoginUserUtil.getLoginUser();
        if (Objects.isNull(loginUser)) {
            return Result.error("获取失败，请重新登录");
        }
        DeptEntity dept = departService.getById(loginUser.getDeptId());
        UserEntity sysUser = sysUserService.getById(loginUser.getId());
        loginUser.setJobDes(sysUser.getJobDes())
                 .setBirthday(sysUser.getBirthday())
                 .setEmail(sysUser.getEmail())
                 .setMobile(sysUser.getMobile())
                 .setSex(sysUser.getSex())
                 .setUserName(sysUser.getUserName())
                 .setNickName(sysUser.getNickName());
        if (Objects.nonNull(dept)) {
            loginUser.setDeptJobDes(dept.getDeptJobDes());
        }
        if (Objects.nonNull(dept)) {
            if (StrUtil.isNotBlank(dept.getRouteCode())) {
                List<String> codes = Arrays.asList(dept.getRouteCode().split(","));
                loginUser.setSubCompanyCode(codes.get(1));
                loginUser.setCompanyCode(codes.get(0));
            }
            loginUser.setDeptCode(dept.getRouteCode());
            loginUser.setDeptName(dept.getName());
        }

        List<MenuEntity> userMenuList = menuService.getUserMenuList(loginUser.getId(),Arrays.asList(0),Arrays.asList(3));
        if (!CollectionUtils.isEmpty(userMenuList)) {
            loginUser.setBtnRes(userMenuList.stream().map(MenuEntity::getPerms).collect(Collectors.toSet()));
        }
        return Result.result(loginUser);
    }

    @ApiOperation("获取当前用户信息")
    @PostMapping("/getH5CurrentUserInfo")
    public Object getH5CurrentUserInfo() {
        LoginUser loginUser = LoginUserUtil.getLoginUser();
        if (Objects.isNull(loginUser)) {
            return Result.error("获取失败，请重新登录");
        }
        DeptEntity dept = departService.getById(loginUser.getDeptId());
        UserEntity sysUser = sysUserService.getById(loginUser.getId());
        loginUser.setJobDes(sysUser.getJobDes())
                .setBirthday(sysUser.getBirthday())
                .setEmail(sysUser.getEmail())
                .setMobile(sysUser.getMobile())
                .setSex(sysUser.getSex())
                .setUserName(sysUser.getUserName())
                .setNickName(sysUser.getNickName());
        if (Objects.nonNull(dept)) {
            loginUser.setDeptJobDes(dept.getDeptJobDes());
        }
        if (Objects.nonNull(dept)) {
            if (StrUtil.isNotBlank(dept.getRouteCode())) {
                List<String> codes = Arrays.asList(dept.getRouteCode().split(","));
                loginUser.setSubCompanyCode(codes.get(1));
                loginUser.setCompanyCode(codes.get(0));
            }
            loginUser.setDeptCode(dept.getRouteCode());
            loginUser.setDeptName(dept.getName());
        }

        List<MenuEntity> userMenuList = menuService.getUserMenuList(loginUser.getId(),Arrays.asList(1),Arrays.asList(1,2,3));
        if (!CollectionUtils.isEmpty(userMenuList)) {
            List<MenuPermis> permis = userMenuList.stream()
                    .map(menu -> {
                        MenuPermis mp = new MenuPermis();
                        mp.setId(menu.getId());
                        mp.setPerm(menu.getPerms());
                        mp.setType(menu.getMenuType());
                        return mp;
                    })
                    .collect(Collectors.toList());
            loginUser.setPermis(permis);
        }
        return Result.result(loginUser);
    }

    @ApiOperation("获取当前用户信息")
    @RequestMapping("/getCurrentUser")
    public Object getCurrentUser() {
        LoginUser loginUser = LoginUserUtil.getLoginUser();
        if (Objects.isNull(loginUser)) {
            return Result.error("获取失败，请重新登录");
        }
//        DeptEntity dept = departService.getById(loginUser.getDeptId());
        UserEntity sysUser = sysUserService.getById(loginUser.getId());
        loginUser.setJobDes(sysUser.getJobDes())
                .setBirthday(sysUser.getBirthday())
                .setEmail(sysUser.getEmail())
                .setMobile(sysUser.getMobile())
                .setSex(sysUser.getSex())
                .setUserName(sysUser.getUserName())
                .setNickName(sysUser.getNickName());
//        if (Objects.nonNull(dept)) {
//            loginUser.setDeptJobDes(dept.getDeptJobDes());
//        }
//        if (Objects.nonNull(dept)) {
//            if (StrUtil.isNotBlank(dept.getRouteCode())) {
//                List<String> codes = Arrays.asList(dept.getRouteCode().split(","));
//                loginUser.setSubCompanyCode(codes.get(1));
//                loginUser.setCompanyCode(codes.get(0));
//            }
//            loginUser.setDeptCode(dept.getRouteCode());
//            loginUser.setDeptName(dept.getName());
//        }
        return Result.result(loginUser);
    }

    @ApiOperation("获取AccessToken")
    @PostMapping("/sendVerifyCode")
    public Result sendLoginVerifyCode(String mobile) {
        if (StrUtil.isBlank(mobile)) {
            return Result.error("参数错误");
        }
        UserEntity userAccount = sysUserService.getOne(new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getMobile,mobile));
        if (userAccount == null) {
            return Result.error("手机号错误,该手机号用户不存在");
        }
        try {
            return  smsLogService.sendLoginSmsCode(mobile);
        }catch (Exception e) {
            return  Result.error(e.getMessage());
        }
    }



//    public static void main(String[] args) {
//
//        String baseUrl = "https://openapi.liblibai.cloud";
//
//        String secretKey = "MyJwnqGd1h_W__ENlx_ywK-RpkHTeJd7";
//        // 请求API接口的uri地址
//        String uri = "/api/generate/webui/status";
//        // 当前毫秒时间戳
//        Long timestamp = System.currentTimeMillis();
//        // 随机字符串
//        String signatureNonce = RandomStringUtils.randomAlphanumeric(10);
//        // 拼接请求数据
//        String content = uri + "&" + timestamp + "&" + signatureNonce;
//
//        try {
//            // 生成签名
//            SecretKeySpec secret = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
//            Mac mac = Mac.getInstance("HmacSHA1");
//            mac.init(secret);
//            String signature =  Base64.encodeBase64URLSafeString(mac.doFinal(content.getBytes()));
//            String url = baseUrl+uri+"?AccessKey=kaB5IBReZKiU9LiIJPbl6g&Signature="+signature+"&Timestamp="+timestamp+"&SignatureNonce="+signatureNonce;
//            System.out.println("url :"+url);
//        } catch (NoSuchAlgorithmException e) {
//           log.error("NoSuchAlgorithmException -- error--",e);
//        } catch (InvalidKeyException e) {
//            log.error("InvalidKeyException -- error--",e);
//        }
//    }
}
