package com.judong.chuanyiserver.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONObject;
import com.judong.chuanyiserver.dao.UserDao;
import com.judong.chuanyiserver.entity.Permission;
import com.judong.chuanyiserver.entity.Role;
import com.judong.chuanyiserver.entity.User;
import com.judong.chuanyiserver.enums.ResultEnum;
import com.judong.chuanyiserver.exception.CustomException;
import com.judong.chuanyiserver.service.UserService;
import com.judong.chuanyiserver.util.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserUtil userUtil;

    @Override
    public Result getCodeImage(boolean hasPubKey) {
        JSONObject jsonObject = new JSONObject();
        // 定义图形验证码的长、宽、验证码字符数、干扰线宽度
        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(126, 40, 4, 4);
        // 图形验证码写出，可以写出到文件，也可以写出到流
        String captchaCode = captcha.getCode();
        HttpServletRequest request = userUtil.getRequest();
        String sessionId = request.getRequestedSessionId();
        if (Blank.isEmpty(sessionId)) {
            sessionId = request.getSession().getId();
        }
        // 设置验证码有效时间
        redisUtil.set(sessionId + "-captcha", captchaCode, ConstantStr.ONE_MINUTE);
        jsonObject.put("uid", sessionId);
        jsonObject.put("verifyCode", captcha.getImageBase64());
        if (hasPubKey) {
            jsonObject.put("publicKey", RSAUtil.PUBLIC_KEY);
        }
        return Result.ok(jsonObject);
    }

    /**
     * 前端用户登录
     *
     * @param user
     * @return
     */
    @Override
    public Result frontUserLogin(User user) {
        try {
            user.setPassword(RSAUtil.decrypt(user.getPassword(), "UTF-8"));
        } catch (Exception e) {
            throw new CustomException(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), ResultEnum.REQUEST_WRONGPARAMS.getRespMsg());
        }
        User isExistUser = userDao.getUserByNamePass(user.getUserName(), EncryptUtils.StrToMD5(user.getPassword()));
        if (Blank.isEmpty(isExistUser)) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "用户名或密码错误");
        }
        // 校验验证码
        String storeCode = Convert.toStr(redisUtil.get(user.getUid() + "-captcha"));
        if (Blank.isEmpty(storeCode)) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "验证码失效，请重新获取验证码");
        }
        if (!user.getVerifyCode().equals(storeCode)) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "输入的验证码不正确");
        }
        // 验证码通过则删除验证码
        redisUtil.del(user.getUid() + "-captcha");
        JSONObject json = new JSONObject();
        isExistUser.setPassword("");
        json.put("user", isExistUser);
        List<Integer> roleIdList = userDao.getRoleIdListByUserId(isExistUser.getUserId());
        if (Blank.isEmpty(roleIdList)) {
            return Result.no(ResultEnum.NO_OPERATION_AUTHORITY.getRespCode(), "没有角色信息");
        }
        json.put("roleIdList", roleIdList);
        List<Permission> permissionList = userDao.getPermissionByRoleList(roleIdList);
        if (Blank.isEmpty(permissionList)) {
            return Result.no(ResultEnum.NO_OPERATION_AUTHORITY.getRespCode(), "没有权限信息");
        }
        json.put("permissionList", permissionList);
        //生成token
        String token = TokenUtil.token(isExistUser.getUserName(), ConstantStr.HALF_HOUR);
        json.put("token", token);
        redisUtil.set(token, isExistUser.getUserId(), ConstantStr.HALF_HOUR);
        //更新用户登录状态
        if (userDao.updateLoginState(isExistUser.getUserId()) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), "更新登录状态失败");
        }
        return Result.ok(json);
    }

    /**
     * 后台管理系统登录
     *
     * @param user
     * @return
     */
    @Override
    public Result backUserLogin(User user) {
        try {
            user.setPassword(RSAUtil.decrypt(user.getPassword(), "UTF-8"));
        } catch (Exception e) {
            throw new CustomException(ResultEnum.SERVER_ERROR.getRespCode(), ResultEnum.SERVER_ERROR.getRespMsg());
        }
        User isExistUser = userDao.getUserByNamePass(user.getUserName(), EncryptUtils.StrToMD5(user.getPassword()));
        if (Blank.isEmpty(isExistUser)) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "用户名或密码错误");
        }
        // 校验验证码
        String storeCode = Convert.toStr(redisUtil.get(user.getUid() + "-captcha"));
        if (Blank.isEmpty(storeCode)) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "验证码失效，请重新获取验证码");
        }
        if (!user.getVerifyCode().equals(storeCode)) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "输入的验证码不正确");
        }
        // 验证码通过则删除验证码
        redisUtil.del(user.getUid() + "-captcha");
        List<Integer> roleIdList = userDao.getRoleIdListByUserId(isExistUser.getUserId());
        if (Blank.isEmpty(roleIdList)) {
            return Result.no(ResultEnum.NO_OPERATION_AUTHORITY.getRespCode(), ResultEnum.NO_OPERATION_AUTHORITY.getRespMsg());
        }
        for (Integer roleId : roleIdList) {
            if (roleId == ConstantStr.ROLE_ADMIN) {
                JSONObject json = new JSONObject();
                isExistUser.setPassword("");
                json.put("user", isExistUser);
                json.put("roleIdList", roleIdList);
                List<Permission> permissionList = userDao.getPermissionByRoleList(roleIdList);
                if (Blank.isEmpty(permissionList)) {
                    return Result.no(ResultEnum.NO_OPERATION_AUTHORITY.getRespCode(), "没有权限信息");
                }
                json.put("permissionList", permissionList);
                //生成token
                String token = TokenUtil.token(isExistUser.getUserName(), ConstantStr.HALF_HOUR);
                json.put("token", token);
                redisUtil.set(token, isExistUser.getUserId(), ConstantStr.HALF_HOUR);
                return Result.ok(json);
            }
        }
        return Result.no(ResultEnum.NO_OPERATION_AUTHORITY.getRespCode(), ResultEnum.NO_OPERATION_AUTHORITY.getRespMsg());
    }

    /**
     * 添加用户
     *
     * @param userName
     * @param password
     * @return
     */
    @Override
    public synchronized Result addUser(String userName, String password) {
        User user = userDao.getUserByName(userName);
        if (Blank.isNotEmpty(user)) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "该用户名已被使用，请更换其他用户名");
        }
        String userId = UUID.randomUUID().toString().replaceAll("-", "");
        if (userDao.addUser(userId, userName, EncryptUtils.StrToMD5(password)) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), "新增失败");
        }
        //新增用户默认角色为2
        if (userDao.addUserRole(userId, ConstantStr.ROLE_STAFF) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), "新增失败");
        }
        return Result.ok("添加用户成功");
    }

    /**
     * 新增角色
     *
     * @param roleName
     * @return
     */
    @Override
    public synchronized Result addRole(String roleName) {
        if (Blank.isNotEmpty(userDao.getRoleByName(roleName))) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "该角色名已被使用，请更换其他角色名");
        }
        if (userDao.addRole(roleName) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), "新增失败");
        }
        return Result.ok("添加角色成功");
    }

    @Override
    public synchronized Result assignRole(String userId, List<Role> roleList) {
        //查询出拥有新旧角色集合拥有的公共角色
        List<Role> shareRoleList = userDao.getShareRoleList(userId, roleList);
        //增加新增的角色信息
        List<Role> newRoleList = new ArrayList<>();
        if (Blank.isEmpty(shareRoleList)) {
            newRoleList = roleList;
            //删除原来的角色
            userDao.deleteUserRoleByUserId(userId);
        } else {
            for (int i = 0; i < roleList.size(); i++) {
                Boolean flage = false;
                for (int j = 0; j < shareRoleList.size(); j++) {
                    if (roleList.get(i).getId() == shareRoleList.get(j).getId()) {
                        flage = true;
                        break;
                    }
                }
                if (!flage) {
                    newRoleList.add(roleList.get(i));
                }
            }
            //删除不在公共角色的旧角色Id
            List<Integer> oldRoleIdList = userDao.getNoShareOldRoleList(userId, shareRoleList);
            if (Blank.isNotEmpty(oldRoleIdList)) {
                userDao.deleteUserRole(userId, oldRoleIdList);
            }
        }
        if (Blank.isNotEmpty(newRoleList)) {
            userDao.addRoleList(userId, newRoleList);
        }
        return Result.ok("分配角色成功");
    }

    @Override
    public Result userLoginOut() {
        String token = userUtil.getToken();
        redisUtil.del(token);
        return Result.ok(true);
    }

    @Override
    public Result getUserPage(int page, int limit) {
        JSONObject jsonObject = new JSONObject();
        Long count = userDao.getUserCount();
        Long startNum = Long.valueOf((page - 1) * limit);
        List<User> userList = userDao.getUserPage(startNum, Long.valueOf(limit));
        jsonObject.put("count", count);
        jsonObject.put("userList", userList);
        return Result.ok(jsonObject);
    }

    @Override
    public Result getUserById(String userId) {
        String tokenUserId = userUtil.getCurrentUserId();
        List<Integer> roleIdList = userDao.getRoleIdListByUserId(tokenUserId);
        for (Integer roleId : roleIdList) {
            if (roleId == ConstantStr.ROLE_ADMIN) {
                return Result.ok(userDao.getUserById(userId));
            }
        }
        if (userId.equals(tokenUserId)) {
            return Result.ok(userDao.getUserById(userId));
        }
        return Result.no(ResultEnum.NO_OPERATION_AUTHORITY.getRespCode(), ResultEnum.NO_OPERATION_AUTHORITY.getRespMsg());
    }

    @Override
    public Result updateUserStateById(String userId, Integer userState) {
        if (userState != ConstantStr.NORMAL_USE && userState != ConstantStr.LOCK_USER && userState != ConstantStr.TOMBSTONE) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "用户状态参数只能为0,1,2");
        }
        String msg = "";
        if (userState == ConstantStr.NORMAL_USE) {
            msg = "用户变更为正常用户";
        } else if (userState == ConstantStr.LOCK_USER) {
            msg = "锁定用户";
        } else if (userState == ConstantStr.TOMBSTONE) {
            msg = "删除用户";
        }
        if (userDao.updateUserState(userId, userState) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), msg + "失败");
        }
        return Result.ok(msg + "成功");
    }

    @Override
    public synchronized Result updateUser(User user) {
        if (Blank.isEmpty(user.getUserId()) || Blank.isEmpty(user.getUserName()) || Blank.isEmpty(user.getPassword())) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "用户Id不能为空，用户名不能为空，密码不能为空");
        }
        if (Blank.isNotEmpty(userDao.getUserByNameNoId(user.getUserId(), user.getUserName()))) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "该用户名已被使用，请更换其他用户名");
        }
        user.setPassword(EncryptUtils.StrToMD5(user.getPassword()));
        if (userDao.updateUser(user) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), "修改用户失败");
        }
        return Result.ok("修改用户成功");
    }

    @Override
    public synchronized Result updateRole(Role role) {
        if (Blank.isEmpty(role.getId()) || Blank.isEmpty(role.getRoleName())) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "角色Id和角色名称不能为空");
        }
        if (Blank.isNotEmpty(userDao.getRoleByNoIdName(role.getId(), role.getRoleName()))) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "已存在该角色名，请更换角色名称");
        }
        if (userDao.updateRole(role) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), "修改角色失败");
        }
        return Result.ok("修改角色成功");
    }

    @Override
    public Result getRoleListByPage(Integer page, Integer limit) {
        JSONObject jsonObject = new JSONObject();
        Long count = userDao.getRoleCount();
        Long startNum = Long.valueOf((page - 1) * limit);
        List<Role> roleList = userDao.getRoleListByPage(startNum, Long.valueOf(limit));
        jsonObject.put("count", count);
        jsonObject.put("roleList", roleList);
        return Result.ok(jsonObject);
    }

    @Override
    public Result getRoleById(Integer id) {
        return Result.ok(userDao.getRoleById(id));
    }

    @Override
    public synchronized Result addPermission(Permission permission) {
        if (Blank.isEmpty(permission.getPermissionUrl()) || Blank.isEmpty(permission.getPermissionName())) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "权限路径和名称不能为空");
        }
        if (Blank.isNotEmpty(userDao.getPermissionByUrl(permission.getPermissionUrl()))) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "该路径已分配权限，请更换其他路径");
        }
        if (userDao.addPermission(permission) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), "新增权限失败");
        }
        return Result.ok("新增资源权限成功");
    }

    @Override
    public synchronized Result updatePermission(Permission permission) {
        if (Blank.isEmpty(permission.getId()) || Blank.isEmpty(permission.getPermissionUrl()) || Blank.isEmpty(permission.getPermissionName())) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "权限id，路径,名称不能为空");
        }
        if (Blank.isNotEmpty(userDao.getPermissionByNoIdUrl(permission.getId(), permission.getPermissionUrl()))) {
            return Result.no(ResultEnum.REQUEST_WRONGPARAMS.getRespCode(), "已存在该权限路径，请更换权限路径");
        }
        if (userDao.updatePermission(permission) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), "修改权限失败");
        }
        return Result.ok("修改权限成功");
    }

    @Override
    public Result getPermissionById(Integer id) {
        return Result.ok(userDao.getPermissionById(id));
    }

    @Override
    public Result getPermissionListByPage(Integer page, Integer limit) {
        JSONObject jsonObject = new JSONObject();
        Long count = userDao.getPermissionCount();
        Long startNum = Long.valueOf((page - 1) * limit);
        List<Permission> permissionList = userDao.getPermissionListByPage(startNum, Long.valueOf(limit));
        jsonObject.put("count", count);
        jsonObject.put("permissionList", permissionList);
        return Result.ok(jsonObject);
    }

    @Override
    public Result deletePermissionById(Integer id) {
        if (userDao.deletePermissionById(id) <= 0) {
            return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), "删除权限失败");
        }
        userDao.deleteRolePermissionById(id);
        return Result.ok("删除权限成功");
    }

    @Override
    public Result assignPermission(int roleId, List<Permission> permissionList) {
        List<Permission> sharePermissionList = userDao.getSharePermissionList(roleId, permissionList);
        List<Permission> newPermissionList = new ArrayList<>();
        if (Blank.isEmpty(sharePermissionList)) {
            newPermissionList = permissionList;
            //删除原来的角色
            userDao.deleteRolePermissionByRoleId(roleId);
        } else {
            for (int i = 0; i < permissionList.size(); i++) {
                Boolean flage = false;
                for (int j = 0; j < sharePermissionList.size(); j++) {
                    if (permissionList.get(i).getId() == sharePermissionList.get(j).getId()) {
                        flage = true;
                        break;
                    }
                }
                if (!flage) {
                    newPermissionList.add(permissionList.get(i));
                }
            }
            //删除不在公共角色的旧角色Id
            List<Integer> oldPermissionIdList = userDao.getNoShareOldPermissionList(roleId, sharePermissionList);
            if (Blank.isNotEmpty(oldPermissionIdList)) {
                userDao.deleteRolePermission(roleId, oldPermissionIdList);
            }
        }
        if (Blank.isNotEmpty(newPermissionList)) {
            userDao.addPermissionList(roleId, newPermissionList);
        }
        return Result.ok("分配权限成功");
    }
}
