package pwc.taxtech.atms.service.impl;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import pwc.taxtech.atms.common.AuthUserHelper;
import pwc.taxtech.atms.common.CheckState;
import pwc.taxtech.atms.common.CommonConstants;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.common.OperateLogType;
import pwc.taxtech.atms.common.OperationAction;
import pwc.taxtech.atms.common.OperationModule;
import pwc.taxtech.atms.common.UserLoginType;
import pwc.taxtech.atms.common.UserStatus;
import pwc.taxtech.atms.common.message.UserMessage;
import pwc.taxtech.atms.constant.DimensionConstant;
import pwc.taxtech.atms.constant.PermissionCode;
import pwc.taxtech.atms.constant.PermissionUrl;
import pwc.taxtech.atms.dao.PermissionMapper;
import pwc.taxtech.atms.dao.RoleMapper;
import pwc.taxtech.atms.dao.RolePermissionMapper;
import pwc.taxtech.atms.dao.UserMapper;
import pwc.taxtech.atms.dao.UserOrganizationMapper;
import pwc.taxtech.atms.dao.UserRoleMapper;
import pwc.taxtech.atms.data.RoleData;
import pwc.taxtech.atms.dpo.RoleInfo;
import pwc.taxtech.atms.dpo.UserDto;
import pwc.taxtech.atms.dpo.UserRoleInfo;
import pwc.taxtech.atms.dto.AtmsTokenDto;
import pwc.taxtech.atms.dto.LoginInputDto;
import pwc.taxtech.atms.dto.LoginOutputDto;
import pwc.taxtech.atms.dto.OperationResultDto;
import pwc.taxtech.atms.dto.UpdateLogParams;
import pwc.taxtech.atms.dto.organization.DimensionRoleDto;
import pwc.taxtech.atms.dto.organization.SimpleRoleDto;
import pwc.taxtech.atms.dto.permission.OrganizationPermissionDto;
import pwc.taxtech.atms.dto.permission.OrganizationPermissionKeyDto;
import pwc.taxtech.atms.dto.permission.PermissionDto;
import pwc.taxtech.atms.dto.permission.PermissionKeyDto;
import pwc.taxtech.atms.dto.permission.UserPermissionDto;
import pwc.taxtech.atms.dto.permission.UserPermissionKeyDto;
import pwc.taxtech.atms.dto.user.UserAndUserRoleSaveDto;
import pwc.taxtech.atms.dto.user.UserRoleDimensionValueDto;
import pwc.taxtech.atms.dto.user.VMUser;
import pwc.taxtech.atms.dto.user.WebUserDto;
import pwc.taxtech.atms.entity.*;
import pwc.taxtech.atms.entity.UserRoleExample.Criteria;
import pwc.taxtech.atms.exception.ApplicationException;
import pwc.taxtech.atms.security.AtmsPasswordEncoder;
import pwc.taxtech.atms.security.JwtAuthenticationService;
import pwc.taxtech.atms.security.JwtUtil;
import pwc.taxtech.atms.security.LdapAuthenticationProvider;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 */
@Service
public class UserServiceImpl extends AbstractService {
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private RolePermissionMapper rolePermissionMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private AtmsPasswordEncoder atmsPasswordEncoder;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private RoleServiceImpl roleService;
    @Autowired
    private MenuServiceImpl menuService;
    @Autowired
    private UserAccountServiceImpl userAccountService;
    @Autowired
    private LdapAuthenticationProvider ldapAuthenticationProvider;
    @Autowired
    private AuthUserHelper authUserHelper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private UserOrganizationMapper userOrganizationMapper;
    @Autowired
    private OperationLogServiceImpl operationLogService;
    @Autowired
    private OrganizationServiceImpl organizationService;
    @Autowired
    private UserRoleServiceImpl userRoleService;
    @Autowired
    private RoleData roleData;
    @Autowired
    private JwtAuthenticationService jwtAuthenticationService;

    @Value("${api.url}")
    private String apiUrl;

    public UserPermissionDto getUserPermission(String userName) {
        User user = userMapper.selectByUserNameIgnoreCase(userName);
        if (user == null) {
            return new UserPermissionDto();
        }
        UserPermissionDto userPermission = new UserPermissionDto();
        userPermission.setId(user.getId());
        userPermission.setIsAdmin(user.getIsAdmin());
        userPermission.setIsSuperAdmin(user.getIsSuperAdmin());
        userPermission.setUserName(userName);

        List<OrganizationPermissionDto> organizationPermissionDtos = new ArrayList<>();
        userPermission.setOrganizationPermissionList(organizationPermissionDtos);
        List<PermissionDto> permissionDtos = new ArrayList<>();
        userPermission.setPermissionList(permissionDtos);

        List<UserRole> urList = findUserRolesByUserId(user.getId());
        List<RolePermission> rolePermissionList = findAllRolePermissions();
        List<Permission> permissionList = findPermissionsByIsActive(CommonConstants.ACTIVE_STATUS);

        List<RolePermission> newRolePermissions = new ArrayList<>();
        List<Permission> newPermissions = new ArrayList<>();
        for (UserRole userRole : urList) {
            if (userRole.getRoleId() == null) {
                continue;
            }
            for (RolePermission rolePermission : rolePermissionList) {
                if (rolePermission.getRoleId() != null && rolePermission.getRoleId().equals(userRole.getRoleId())) {
                    newRolePermissions.add(rolePermission);
                }
            }
        }
        for (RolePermission rolePermission : newRolePermissions) {
            if (rolePermission.getPermissionId() == null) {
                continue;
            }
            for (Permission permission : permissionList) {
                if (permission.getId().equals(rolePermission.getPermissionId())) {
                    newPermissions.add(permission);
                }
            }
        }
        // 把原始的角色信息加上
        List<PermissionDto> userRoleList = newPermissions.stream().map(this::rotatePermissionToPermissionDto).distinct()
                .collect(Collectors.toList());

        // 获取机构权限列表
        userPermission
                .setOrganizationPermissionList(getOrganizationPermissionList(user, rolePermissionList, permissionList));

        List<String> menuIdList = userRoleList.stream()
                .filter(oneUserRole -> StringUtils.hasText(oneUserRole.getMenuId()))
                .map(oneUserRole -> oneUserRole.getMenuId()).collect(Collectors.toList());

        List<Menu> menuList = menuService.findByIsActive(CommonConstants.ACTIVE_STATUS);
        userPermission.setPermissionList(userRoleList);
        List<String> urls = new ArrayList<>();
        for (String item : menuIdList) {
            List<String> temp = getNavigationUrl(item, menuList);
            urls.addAll(temp);
        }

        if (!urls.isEmpty()) {
            // 把Admin首页地址加上
            urls.add(CommonConstants.AdminHomePage);
        }
        userPermission.setNavigationUrlList(urls);

        // 查看用户
        if (userRoleList.stream().anyMatch(oneUserRole -> PermissionCode.QueryUserCode.equals(oneUserRole.getCode()))) {
            userPermission.getNavigationUrlList().addAll(PermissionUrl.ExtraQueryUseList);
        }

        // 查看机构
        if (userRoleList.stream()
                .anyMatch(oneUserRole -> PermissionCode.QueryOranizationCode.equals(oneUserRole.getCode()))) {
            userPermission.getNavigationUrlList().addAll(PermissionUrl.ExtraQueryOranizationList);
        }

        // 查看事业部、区域、机构、自定义维度dashboard 特殊处理
        if (userRoleList.stream()
                .anyMatch(oneUserRole -> PermissionCode.DimensionPermissionCodeList.contains(oneUserRole.getCode()))) {
            userPermission.getNavigationUrlList().addAll(PermissionUrl.ExtraQueryBusinessUnit);
        }

        userPermission.setNavigationUrlList(
                userPermission.getNavigationUrlList().stream().distinct().collect(Collectors.toList()));
        return userPermission;
    }

    private List<String> getNavigationUrl(String menuId, List<Menu> menuList) {
        List<String> retlist = new ArrayList<>();
        List<Menu> findMenus = menuList.stream().filter(oneMenu -> menuId.equals(oneMenu.getId()))
                .collect(Collectors.toList());
        if (findMenus.isEmpty()) {
            return retlist;
        }
        Menu findMenu = findMenus.get(0);
        if (StringUtils.hasText(findMenu.getParentId())) {
            List<String> tempList = getNavigationUrl(findMenu.getParentId(), menuList);
            retlist.addAll(tempList);
        }
        if (StringUtils.hasText(findMenu.getNavigationUrl())) {
            if (CommonConstants.BasicDataManageMenu.equals(findMenu.getId())) {
                return retlist;
            }
            retlist.add(findMenu.getNavigationUrl());
            return retlist;
        }
        return retlist;
    }

    private List<Permission> findPermissionsByIsActive(Boolean isActive) {
        PermissionExample permissionExample = new PermissionExample();
        permissionExample.createCriteria().andIsActiveEqualTo(isActive);
        return permissionMapper.selectByExample(permissionExample);
    }

    private List<UserRole> findUserRolesByUserId(String userId) {
        UserRoleExample userRoleExample = new UserRoleExample();
        userRoleExample.createCriteria().andUserIdEqualTo(userId);
        return userRoleMapper.selectByExample(userRoleExample);
    }

    private List<RolePermission> findAllRolePermissions() {
        return rolePermissionMapper.selectByExample(new RolePermissionExample());
    }

    private PermissionDto rotatePermissionToPermissionDto(Permission permission) {
        PermissionDto permissionDto = new PermissionDto();
        permissionDto.setCode(permission.getCode());
        permissionDto.setId(permission.getId());
        permissionDto.setName(permission.getName());
        permissionDto.setParentId(permission.getParentId());
        permissionDto.setMenuId(permission.getMenuId());
        return permissionDto;
    }

    private PermissionKeyDto rotatePermissionToPermissionKeyDto(Permission permission) {
        PermissionKeyDto permissionKeyDto = new PermissionKeyDto();
        CommonUtils.copyProperties(permission, permissionKeyDto);
        return permissionKeyDto;
    }

    private List<OrganizationPermissionDto> getOrganizationPermissionList(User user,
                                                                          List<RolePermission> rolePermissionList, List<Permission> permissionList) {
        VMUser vmUser = new VMUser();
        vmUser.setId(user.getId());
        vmUser.setEmail(user.getEmail());
        vmUser.setIsAdmin(CommonConstants.ADMIN_STATUS.equals(user.getIsAdmin()));
        vmUser.setOrganizationId(user.getOrganizationId());
        List<OrganizationPermissionDto> retList = new ArrayList<>();
        if (user.getIsSuperAdmin()) {
            return retList;
        }
        List<UserRoleInfo> result = roleService.getUserRoleByUser(vmUser);
        if (result != null && !result.isEmpty()) {
            for (UserRoleInfo org : result) {
                OrganizationPermissionDto orgPermission = new OrganizationPermissionDto();
                orgPermission.setId(org.getOrganizationId());
                orgPermission.setName(org.getOrganizationName());
                List<PermissionDto> permissionDtos = new ArrayList<>();
                orgPermission.setPermissionList(permissionDtos);

                List<RolePermission> rolePermissions = new ArrayList<>();
                for (RoleInfo roleInfo : org.getRoleInfoList()) {
                    for (RolePermission rolePermission : rolePermissionList) {
                        if (roleInfo.getId().equals(rolePermission.getRoleId())) {
                            rolePermissions.add(rolePermission);
                        }
                    }
                }

                List<Permission> permissions = new ArrayList<>();
                for (RolePermission rolePermission : rolePermissions) {
                    if (rolePermission.getPermissionId() == null) {
                        continue;
                    }
                    for (Permission permission : permissionList) {
                        if (rolePermission.getPermissionId().equals(permission.getId())) {
                            permissions.add(permission);
                        }
                    }
                }
                List<PermissionDto> permissionDtoList = permissions.stream().map(this::rotatePermissionToPermissionDto)
                        .distinct().collect(Collectors.toList());
                orgPermission.setPermissionList(permissionDtoList);
                retList.add(orgPermission);
            }
        }
        return retList;
    }

    private List<OrganizationPermissionKeyDto> getOrganizationPermissionKeyList(User user,
                                                                                List<RolePermission> rolePermissionList, List<Permission> permissionList) {
        VMUser vmUser = new VMUser();
        vmUser.setId(user.getId());
        vmUser.setEmail(user.getEmail());
        vmUser.setIsAdmin(CommonConstants.ADMIN_STATUS.equals(user.getIsAdmin()));
        vmUser.setOrganizationId(user.getOrganizationId());
        List<OrganizationPermissionKeyDto> retList = new ArrayList<>();
        if (CommonConstants.ADMIN_STATUS.equals(user.getIsAdmin())) {
            // 如果是admin,则拥有所有权限
            return retList;
        }
        List<UserRoleInfo> result = roleService.getUserRoleByUser(vmUser);
        if (result != null && !result.isEmpty()) {
            for (UserRoleInfo org : result) {
                OrganizationPermissionKeyDto orgPermission = new OrganizationPermissionKeyDto();
                orgPermission.setId(org.getOrganizationId());
                orgPermission.setName(org.getOrganizationName());
                List<PermissionKeyDto> permissionDtos = new ArrayList<>();
                orgPermission.setPermissionList(permissionDtos);

                List<RolePermission> rolePermissions = new ArrayList<>();
                for (RoleInfo roleInfo : org.getRoleInfoList()) {
                    for (RolePermission rolePermission : rolePermissionList) {
                        if (roleInfo.getId().equals(rolePermission.getRoleId())) {
                            rolePermissions.add(rolePermission);
                        }
                    }
                }

                List<Permission> permissions = new ArrayList<>();
                for (RolePermission rolePermission : rolePermissions) {
                    if (rolePermission.getPermissionId() == null) {
                        continue;
                    }
                    for (Permission permission : permissionList) {
                        if (rolePermission.getPermissionId().equals(permission.getId())) {
                            permissions.add(permission);
                        }
                    }
                }
                List<PermissionKeyDto> permissionDtoList = permissions.stream()
                        .map(this::rotatePermissionToPermissionKeyDto).distinct().collect(Collectors.toList());
                orgPermission.setPermissionList(permissionDtoList);
                retList.add(orgPermission);
            }
        }
        return retList;
    }

    private OrganizationPermissionDto rotateUserRoleInfoToOrganizationPermissionDto(UserRoleInfo userRoleInfo) {
        OrganizationPermissionDto organizationPermissionDto = new OrganizationPermissionDto();
        organizationPermissionDto.setId(userRoleInfo.getOrganizationId());
        organizationPermissionDto.setName(userRoleInfo.getOrganizationName());
        List<PermissionDto> permissionDtos = new ArrayList<>();
        organizationPermissionDto.setPermissionList(permissionDtos);
        return organizationPermissionDto;
    }

    public User getUser(String id) {
        return userMapper.selectByPrimaryKey(id);
    }

    public OperationResultDto<LoginOutputDto> login(LoginInputDto input) {
        // return dummyLogin(input);
        return doLogin(input);
    }

    private OperationResultDto<LoginOutputDto> doLogin(LoginInputDto input) {
        logger.debug("doLogin start");
        Assert.notNull(input, "Null input");
        final String inputLoginName = input.getEmail();
        Assert.hasText(inputLoginName, "empty email");
        Assert.hasText(input.getPassword(), "empty password");
        logger.debug("ready to call userMapper.selectByserNameIgnoreCase");
        // 查找用户时需要忽略大小写
        User tempUser = userMapper.selectByUserNameIgnoreCase(inputLoginName);
        logger.debug("print tempUser is null?:{}", tempUser == null);

        // 判断用户是否是正常状态
        final OperationResultDto<LoginOutputDto> loginResult = activeCheck(tempUser);
        final LoginOutputDto loginOutputDto = loginResult.getData();
        if (loginResult.getResult() != null && !loginResult.getResult()) {
            logger.debug(
                    "return loginResult after activeCheck due to loginResult.getResult():{}, loginOutputDto.getCheckState():{}",
                    loginResult.getResult(), loginOutputDto.getCheckState());
            return loginResult;
        }
        Assert.notNull(tempUser, "Null tempUser after calling activeCheck()");
        final boolean isExternalUser = UserLoginType.ExternalUser.equals(tempUser.getLoginType());
        logger.debug("print tempUser.getLoginType():{}", tempUser.getLoginType());
        loginOutputDto.setIsExternalUser(isExternalUser);
        logger.debug("print tempUser.getId():{}", tempUser.getId());
        loginOutputDto.setUserId(tempUser.getId());

        // 根据用户的登录类型选择不同的登录验证方式
        OperationResultDto<LoginOutputDto> newloginResult = null;
        if (isExternalUser) {
            newloginResult = externalUserLogin(tempUser, inputLoginName, input.getPassword());
        } else {
            newloginResult = internalUserLogin(tempUser, inputLoginName, input.getPassword());
        }

        final LoginOutputDto newloginOutputDto = newloginResult.getData();
        // 如果登录失败,则根据失败的次数增加尝试登录次数以及修改用户状态
        if (newloginResult.getResult() != null && !newloginResult.getResult()) {
            if (newloginOutputDto != null
                    && CheckState.WrongPassword.value().equals(newloginOutputDto.getCheckState())) {
                logger.debug("如果登录失败,则根据失败的次数增加尝试登录次数以及修改用户状态");
                userAccountService.dealWithWrongPassword(tempUser);
            }
            return newloginResult;
        }
        newloginOutputDto.setUserId(tempUser.getId());

        // 如果用户登录成功,且尝试登录次数不为0,则重置登录次数
        if (tempUser.getAttemptTimes() != null && tempUser.getAttemptTimes() > 0) {
            logger.debug("如果用户登录成功,且尝试登录次数不为0,则重置登录次数");
            userAccountService.resetAttemptTimes(tempUser);
        } else {
            logger.debug("如果用户登录成功,跳过重置登录次数");
        }

        // 原注释“如果用户为外部用户,且账户状态正常,则需要修改密码”
        // 但是以下的场景不可能发生,InActive的用户会被activeCheck方法拒绝登录
        if (isExternalUser && UserStatus.InActive.value().equals(tempUser.getStatus())) {
            needChangePassword(tempUser, newloginResult);
        }

        if (newloginResult.getResult() != null && newloginResult.getResult()) {
            newloginResult.getData().setMessage("Login success.");
            logger.debug("创建AtmsTokenDto");
            AtmsTokenDto token = new AtmsTokenDto();
            newloginResult.getData().setToken(token);
            String accessToken = jwtUtil.generateToken(inputLoginName, tempUser.getUserName(), tempUser.getId());
            token.setAccess_token(accessToken);
            token.setToken_type("bearer");
            token.setExpires_in(86400000L);
            // api_host可以由atms-web端来赋值
            token.setApi_host("NA");
            token.setVat_api_host(apiUrl);
            token.setTp_url(apiUrl);
            token.setVersion("1.0" + ".0.0");
            token.setUser_name(inputLoginName);
            token.setLocal_name(inputLoginName);
            token.setNeed_change_password(false);
            token.setIs_external_user(isExternalUser);
            token.setUser_id(tempUser.getId());
            logger.debug("创建UserDto");

            /// @see PwC.Tax.Tech.Atms.Web\Controllers\AccountController.cs
            /// C#代码:User = new UserDto { UniqueId = Guid.NewGuid().ToString(), LoginName =
            /// userName, Password = password },
            WebUserDto userDto = new WebUserDto();
            newloginResult.getData().setUser(userDto);
            userDto.setUniqueId(CommonUtils.getUUID());
            userDto.setLoginName(inputLoginName);
            // 参照C#代码设置password
            userDto.setPassword(input.getPassword());
            userDto.setHasValidPeriod(false);
            // 登陆成功后清除缓存中的用户后台权限
            jwtAuthenticationService.removeApiAuthList(tempUser.getId());
        } else {
            logger.error("状态异常");
        }
        if (logger.isDebugEnabled()) {
            logger.debug("print return json:{}", JSON.toJSONString(newloginResult, true));
        }
        return newloginResult;
    }

    private void needChangePassword(User tempUser, OperationResultDto<LoginOutputDto> newloginResult) {
        // 这不可能发生,InActive的用户会被activeCheck方法拒绝登录
        throw new ApplicationException("Not happens");
    }

    private OperationResultDto<LoginOutputDto> internalUserLogin(User tempUser, String username, String password) {
        if (UserLoginType.ADUser.equals(tempUser.getLoginType())) {
            return adLoginCheck(username, password);
        } else {
            return passwordLoginCheck(tempUser, password);
        }
    }

    public OperationResultDto<LoginOutputDto> adLoginCheck(String username, String password) {
        boolean authenticated = ldapAuthenticationProvider.authenticate(username, password);
        if (authenticated) {
            logger.debug("LDAP server return true");
            OperationResultDto<LoginOutputDto> result = new OperationResultDto<>();
            result.setResult(true);
            LoginOutputDto data = new LoginOutputDto();
            data.setCheckState(CheckState.Success.value());
            result.setData(data);
            return result;
        } else {
            logger.debug("LDAP server return false");
            OperationResultDto<LoginOutputDto> result = new OperationResultDto<>();
            result.setResult(false);
            LoginOutputDto data = new LoginOutputDto();
            data.setCheckState(CheckState.WrongPassword.value());
            result.setData(data);
            return result;
        }

    }

    public OperationResultDto<LoginOutputDto> externalUserLogin(User tempUser, String email, String password) {
        return passwordLoginCheck(tempUser, password);
    }

    private OperationResultDto<LoginOutputDto> passwordLoginCheck(User tempUser, String password) {
        logger.debug("externalUserLogin start");
        boolean passwordMatch = atmsPasswordEncoder.matches(password, tempUser.getPassword());
        if (!passwordMatch) {
            logger.debug("密码错误");
            OperationResultDto<LoginOutputDto> result = new OperationResultDto<>();
            result.setResult(false);
            LoginOutputDto data = new LoginOutputDto();
            data.setCheckState(CheckState.WrongPassword.value());
            result.setData(data);
            return result;
        }
        logger.debug("密码校验成功");
        OperationResultDto<LoginOutputDto> result = new OperationResultDto<>();
        result.setResult(true);
        LoginOutputDto data = new LoginOutputDto();
        data.setCheckState(CheckState.Success.value());
        result.setData(data);
        return result;
    }

    public OperationResultDto<LoginOutputDto> activeCheck(User tempUser) {
        if (tempUser == null) {
            OperationResultDto<LoginOutputDto> result = new OperationResultDto<>();
            result.setResult(false);
            LoginOutputDto data = new LoginOutputDto();
            data.setCheckState(CheckState.UserNameNotExist.value());
            result.setData(data);
            return result;
        }
        boolean inactive = tempUser.getStatus() != null && tempUser.getStatus().equals(UserStatus.InActive.value());
        boolean locked = tempUser.getStatus() != null && tempUser.getStatus().equals(UserStatus.Locked.value());
        if (inactive || locked) {
            OperationResultDto<LoginOutputDto> result = new OperationResultDto<>();
            result.setResult(false);
            LoginOutputDto data = new LoginOutputDto();
            data.setCheckState(CheckState.Inactive.value());
            result.setData(data);
            return result;
        }

        OperationResultDto<LoginOutputDto> result = new OperationResultDto<>();
        result.setResult(true);
        LoginOutputDto data = new LoginOutputDto();
        data.setCheckState(CheckState.Success.value());
        result.setData(data);
        return result;
    }

    private OperationResultDto<LoginOutputDto> dummyLogin() {
        OperationResultDto<LoginOutputDto> operationResultDto = new OperationResultDto<>();
        operationResultDto.setResult(true);
        operationResultDto.setResultMsg("OK");
        operationResultDto.setReturnCode(200);
        LoginOutputDto loginOutputDto = new LoginOutputDto();
        operationResultDto.setData(loginOutputDto);
        loginOutputDto.setApiHost("apihost1");
        loginOutputDto.setCheckState(4);
        loginOutputDto.setToken(new AtmsTokenDto());
        return operationResultDto;
    }


    public UserPermissionKeyDto getUserPermissionKey(String userName) {
        User user = userMapper.selectByUserNameIgnoreCase(userName);
        if (user == null) {
            return new UserPermissionKeyDto();
        }
        UserPermissionKeyDto userPermission = new UserPermissionKeyDto();
        userPermission.setId(user.getId());
        userPermission.setIsAdmin(user.getIsAdmin());
        userPermission.setIsSuperAdmin(user.getIsSuperAdmin());
        userPermission.setUserName(userName);

        List<OrganizationPermissionKeyDto> organizationPermissionDtos = new ArrayList<>();
        userPermission.setOrganizationPermissionList(organizationPermissionDtos);
        List<PermissionKeyDto> permissionDtos = new ArrayList<>();
        userPermission.setPermissionList(permissionDtos);

        List<UserRole> urList = findUserRolesByUserId(user.getId());
        List<RolePermission> rolePermissionList = findAllRolePermissions();
        List<Permission> permissionList = findPermissionsByIsActive(CommonConstants.ACTIVE_STATUS);

        List<RolePermission> newRolePermissions = new ArrayList<>();
        List<Permission> newPermissions = new ArrayList<>();
        for (UserRole userRole : urList) {
            if (userRole.getRoleId() == null) {
                continue;
            }
            for (RolePermission rolePermission : rolePermissionList) {
                if (rolePermission.getRoleId() != null && rolePermission.getRoleId().equals(userRole.getRoleId())) {
                    newRolePermissions.add(rolePermission);
                }
            }
        }
        for (RolePermission rolePermission : newRolePermissions) {
            if (rolePermission.getPermissionId() == null) {
                continue;
            }
            for (Permission permission : permissionList) {
                if (permission.getId().equals(rolePermission.getPermissionId())) {
                    newPermissions.add(permission);
                }
            }
        }
        // 把原始的角色信息加上
        List<PermissionKeyDto> userRoleList = newPermissions.stream().map(this::rotatePermissionToPermissionKeyDto)
                .distinct().collect(Collectors.toList());

        // 获取机构权限列表
        userPermission.setOrganizationPermissionList(
                getOrganizationPermissionKeyList(user, rolePermissionList, permissionList));

        List<String> menuIdList = userRoleList.stream()
                .filter(oneUserRole -> StringUtils.hasText(oneUserRole.getMenuId()))
                .map(oneUserRole -> oneUserRole.getMenuId()).collect(Collectors.toList());

        List<Menu> menuList = menuService.findByIsActive(CommonConstants.ACTIVE_STATUS);
        userPermission.setPermissionList(userRoleList);
        List<String> urls = new ArrayList<>();
        for (String item : menuIdList) {
            List<String> temp = getNavigationUrl(item, menuList);
            urls.addAll(temp);
        }

        if (!urls.isEmpty()) {
            // 把Admin首页地址加上
            urls.add(CommonConstants.AdminHomePage);
        }
        userPermission.setNavigationUrlList(urls);

        // 查看用户
        if (userRoleList.stream().anyMatch(oneUserRole -> PermissionCode.QueryUserCode.equals(oneUserRole.getCode()))) {
            userPermission.getNavigationUrlList().addAll(PermissionUrl.ExtraQueryUseList);
        }

        // 查看机构
        if (userRoleList.stream()
                .anyMatch(oneUserRole -> PermissionCode.QueryOranizationCode.equals(oneUserRole.getCode()))) {
            userPermission.getNavigationUrlList().addAll(PermissionUrl.ExtraQueryOranizationList);
        }

        userPermission.setNavigationUrlList(
                userPermission.getNavigationUrlList().stream().distinct().collect(Collectors.toList()));
        return userPermission;
    }

    public List<User> findAllUsers() {
        UserExample userExample = new UserExample();
        return userMapper.selectByExample(userExample);
    }

    public UserDto getUserById(String userId) {
        List<UserDto> userDtos = userMapper.selectUserWithOrgInfoById(userId);
        if (userDtos != null && !userDtos.isEmpty()) {
            return userDtos.get(0);
        }
        return null;
    }

    public OperationResultDto<User> updateUser(UserAndUserRoleSaveDto userDto) {
        OperationResultDto<User> result = checkUserExist(userDto.getUserName(), userDto.getId());
        OperationResultDto<User> operationResultDto = new OperationResultDto<>();
        if (result != null && !BooleanUtils.isTrue(result.getResult())) {
            return result;
        }

        result = checkEmailExist(userDto.getEmail(), userDto.getId());
        if (result != null && !BooleanUtils.isTrue(result.getResult())) {
            return result;
        }
        User user = userMapper.selectByPrimaryKey(userDto.getId());
        Assert.notNull(user, "Null user");
        if (!Objects.equals(userDto.getIsAdmin(), BooleanUtils.isTrue(user.getIsAdmin()))) {
            String userName = authUserHelper.getCurrentAuditor().get();
            User operateUser = userMapper.selectByUserNameIgnoreCase(userName);
            if (operateUser != null && BooleanUtils.isFalse(operateUser.getIsAdmin())) {
                operationResultDto.setResult(false);
                operationResultDto.setResultMsg(UserMessage.HasNoPermission);
                return operationResultDto;
            }
        }

        if (userDto.getRoleIds() == null) {
            userDto.setRoleIds(new ArrayList<>());
        }
        User userOriginal = CommonUtils.copyProperties(user, new User());
        user.setUserName(userDto.getUserName());
        user.setEmail(userDto.getEmail());
        user.setIsAdmin(BooleanUtils.isTrue(userDto.getIsAdmin()));
        user.setOrganizationId(userDto.getOrganizationId());
        user.setUpdateTime(new Date());
        List<UserRole> oldUserRoleList = findUserRoleByUserIdWithoutProjectId(user.getId());
        List<UserRole> userRoleList = new ArrayList<>();
        List<UserRole> needDeleteList = oldUserRoleList.stream()
                .filter(p -> userDto.getRoleIds().stream().noneMatch(sa -> Objects.equals(sa, p.getRoleId())))
                .collect(Collectors.toList());
        for (UserRole userRole : needDeleteList) {
            logger.debug("Start to delete userRole [ {} ]", userRole.getId());
            userRoleMapper.deleteByPrimaryKey(userRole.getId());
        }
//        List<Role> roleQuery = roleMapper.selectByExample(new RoleExample());
        List<Role> roleQuery = roleData.selectByServiceTypeId("All");
        for (String role : userDto.getRoleIds()) {
            if (oldUserRoleList.stream().anyMatch(sa -> Objects.equals(sa.getRoleId(), role))) {
                continue;
            }
            Role r = roleQuery.stream().filter(p -> Objects.equals(p.getId(), role)).findFirst().orElse(null);
            UserRole userRole = new UserRole();
            userRole.setId(CommonUtils.getUUID());
            userRole.setUserId(user.getId());
            userRole.setRoleId(role);
            userRole.setServiceTypeId(r != null ? r.getServiceTypeId() : "");
            userRoleList.add(userRole);
            logger.debug("Start to insert user role [ {} ] with roleId [ {} ]", userRole.getId(), role);
            userRoleMapper.insertSelective(userRole);
        }
        // 添加所属机构的访问权限
        UserOrganization userOrganization = findUserOrganizationByUserIdAndOrganizationId(user.getId(),
                user.getOrganizationId()).stream().findFirst().orElse(null);
        if (userOrganization == null) {
            userOrganization = new UserOrganization();
            userOrganization.setOrganizationId(user.getOrganizationId());
            userOrganization.setUserId(user.getId());
            userOrganization.setIsAccessible(CommonConstants.IsAccessible);
            userOrganization.setId(CommonUtils.getUUID());
            userOrganization.setHasOriginalRole(CommonConstants.HasOriginalRole);
            userOrganizationMapper.insert(userOrganization);
        } else if (BooleanUtils.isFalse(userOrganization.getHasOriginalRole())) {
            userOrganization.setHasOriginalRole(CommonConstants.HasOriginalRole);
            userOrganizationMapper.updateByPrimaryKey(userOrganization);
        }

        userMapper.updateByPrimaryKey(user);
        // 删除以前的用户角色数据日志
        List<UpdateLogParams> oldUserRoleLogs = new ArrayList<>();
        for (UserRole oldUserRole : oldUserRoleList) {
            Role role = roleQuery.stream().filter(sa -> Objects.equals(sa.getId(), oldUserRole.getRoleId())).findFirst()
                    .orElse(null);
            oldUserRoleLogs.add(generateUpdateLogParams(OperateLogType.OperationLogUser.value(),
                    role == null ? "" : role.getName(), userOriginal.getUserName(), OperationAction.Delete.value(),
                    OperationModule.UserRole.value()));
        }
        operationLogService.addOrDeleteDataAddLog(oldUserRoleLogs);
        // 新增新的用户角色数据日志
        List<UpdateLogParams> userRoleLogs = new ArrayList<>();
        for (UserRole userRole : userRoleList) {
            Role role = roleQuery.stream().filter(sa -> Objects.equals(sa.getId(), userRole.getRoleId())).findFirst()
                    .orElse(null);
            userRoleLogs.add(
                    generateUpdateLogParams(OperateLogType.OperationLogUser.value(), role == null ? "" : role.getName(),
                            userOriginal.getUserName(), OperationAction.New.value(), OperationModule.UserRole.value()));
        }
        operationLogService.addOrDeleteDataAddLog(userRoleLogs);
        // 更新用户信息日志
        UpdateLogParams updateLogParams = generateUpdateLogParams(OperateLogType.OperationLogUser.value(), "",
                userOriginal.getUserName(), OperationAction.Update.value(), OperationModule.User.value());
        updateLogParams.setComment("");
        updateLogParams.setUpdateState(user);
        updateLogParams.setOriginalState(userOriginal);
        operationLogService.updateDataAddLog(updateLogParams);
        operationResultDto.setResult(true);
        return operationResultDto;
    }

    private UpdateLogParams generateUpdateLogParams(Integer logType, String operationContent, String operationObject,
                                                    Integer action, Integer module) {
        UpdateLogParams updateLogParams = new UpdateLogParams();
        updateLogParams.setOperateLogType(logType);
        updateLogParams.setOperationContent(operationContent);
        updateLogParams.setOperationObject(operationObject);
        updateLogParams.setOperationAction(action);
        updateLogParams.setOperationModule(module);
        return updateLogParams;
    }

    public List<UserOrganization> findUserOrganizationByUserIdAndOrganizationId(String userId, String organizationId) {
        UserOrganizationExample userOrganizationExample = new UserOrganizationExample();
        pwc.taxtech.atms.entity.UserOrganizationExample.Criteria criteria = userOrganizationExample.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andOrganizationIdEqualTo(organizationId);
        return userOrganizationMapper.selectByExample(userOrganizationExample);
    }

    public UserDto getUserByDto(UserDto userParam) {
        User user = userMapper.selectByUserName(userParam.getUserName());
        UserDto dto = null;
        if (user != null) {
            dto = new UserDto();
            CommonUtils.copyProperties(user, dto);
        }
        return dto;
    }

    private List<UserRole> findUserRoleByUserIdWithoutProjectId(String userId) {
        UserRoleExample userRoleExample = new UserRoleExample();
        Criteria criteria = userRoleExample.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andProjectIdIsNull();
        return userRoleMapper.selectByExample(userRoleExample);
    }

    public OperationResultDto<User> checkUserExist(String userName, String userId) {
        User user = null;
        OperationResultDto<User> operationResultDto = new OperationResultDto<>();
        if (CommonConstants.EMPTY_UUID.equals(userId)) {
            user = userMapper.selectByUserNameIgnoreCase(userName);
        } else {
            UserDto userDto = new UserDto();
            userDto.setId(userId);
            userDto.setUserName(userName);
            user = userMapper.selectUserWithSameUserName(userDto);
        }
        if (user != null && user.getId() != null) {
            operationResultDto.setResult(false);
            operationResultDto.setResultMsg(UserMessage.UserExistsInfo);
            return operationResultDto;
        }
        operationResultDto.setResult(true);
        return operationResultDto;
    }

    public OperationResultDto<User> checkEmailExist(String email, String userId) {
        User user = null;
        OperationResultDto<User> operationResultDto = new OperationResultDto<>();
        if (CommonConstants.EMPTY_UUID.equals(userId)) {
            user = userMapper.selectByEmailIgnoreCase(email);
        } else {
            UserDto userDto = new UserDto();
            userDto.setId(userId);
            userDto.setEmail(email);
            user = userMapper.selectUserWithSameEmail(userDto);
        }
        if (user != null && user.getId() != null) {
            operationResultDto.setResult(false);
            operationResultDto.setResultMsg(UserMessage.EmailRegisted);
            return operationResultDto;
        }
        operationResultDto.setResult(true);
        return operationResultDto;
    }

    public void deleteUserDimensionValue(DimensionRoleDto dto, String userId) {
        if (dto == null || userId == null) {
            throw new ApplicationException(CommonConstants.JSONNULLOBJECT);
        }
        UserDimensionValueExample userDimensionValueExample = new UserDimensionValueExample();
        userDimensionValueExample.createCriteria().andUserIdEqualTo(userId).andDimensionIdEqualTo(dto.getDimensionId())
                .andDimensionValueIdEqualTo(dto.getDimensionValueId());
        UserDimensionValue userDimensionValue = userDimensionValueMapper.selectByExample(userDimensionValueExample)
                .stream().findFirst().orElse(null);
        if (userDimensionValue != null) {
            List<String> roleIdList = dto.getRoleList().stream().map(SimpleRoleDto::getRoleId).collect(toList());
            UserDimensionValueRoleExample userDimensionValueRoleExample = new UserDimensionValueRoleExample();
            userDimensionValueRoleExample.createCriteria().andUserDimensionValueIdEqualTo(userDimensionValue.getId())
                    .andRoleIdIn(roleIdList);
            List<UserDimensionValueRole> items = userDimensionValueRoleMapper
                    .selectByExample(userDimensionValueRoleExample);
            userDimensionValueMapper.deleteByPrimaryKey(userDimensionValue.getId());
            for (UserDimensionValueRole item : items) {
                logger.debug("Start to delete UserDimensionValueRole [ {} ]", item.getId());
                userDimensionValueRoleMapper.deleteByPrimaryKey(item.getId());
            }
        }
    }

    /**
     * 机构用户界面,弹框权限编辑卡片,做删除 如果是维度上的,修改可以继承,还是不可继承 删除,如果是附加原始角色,修改标记Hasorignialrole to
     * 0 删除,如果是附加附加角色,则删除
     */
    @SuppressWarnings("rawtypes")
    public OperationResultDto deleteUserOrg(List<UserRoleDimensionValueDto> userRoleList) {
        if (userRoleList == null) {
            throw new ApplicationException(CommonConstants.JSONNULLOBJECT);
        }
        for (UserRoleDimensionValueDto r : userRoleList) {
            // OrgCustomDto dimension =
            // organizationService.getDimensionValueName(r.getDimensionId(),
            // r.getDimensionValueId());
            // String dimensionName = dimension.getDimensionName();
            // String dimensionValueName = dimension.getDimensionValueName();

            String operateUserName = userRoleService.getUserDtoById(r.getUserId()).getUserName();
            String orgName = userRoleService.getOrgDtoById(r.getOrganizationId()).getName();
            // 如果角色是附加的,附加有附加原始,和附加额外的
            if (DimensionConstant.ExtraOrgDimensionId.equals(r.getDimensionId())) {
                UserOrganization userOrg = findUserOrganizationByUserIdAndOrganizationId(r.getUserId(),
                        r.getOrganizationId()).stream().findFirst().orElse(null);
                // 附加额外角色,删除
                if (DimensionConstant.ExtraOrgDimensionValueId.equals(r.getDimensionValueId()) && userOrg != null) {
                    UserOrganizationRoleExample userOrganizationRoleExample = new UserOrganizationRoleExample();
                    userOrganizationRoleExample.createCriteria().andUserOrganizationIdEqualTo(userOrg.getId());
                    List<UserOrganizationRole> target = userOrganizationRoleMapper
                            .selectByExample(userOrganizationRoleExample);
                    for (UserOrganizationRole oneTarget : target) {
                        logger.debug("Start to delete UserOrganizationRole [ {} ]", oneTarget.getId());
                        userOrganizationRoleMapper.deleteByPrimaryKey(oneTarget.getId());
                        // 添加日志
//                        Role role = roleMapper.selectByPrimaryKey(oneTarget.getRoleId());
                        Role role = roleData.selectByPrimaryKey(oneTarget.getRoleId());
                        String roleName = role == null ? "" : role.getName();
                        operationLogService
                                .addOrDeleteDataAddLog(generateUpdateLogParams(OperateLogType.OperationLogUser.value(),
                                        orgName + CommonConstants.DashSignSeparator + operateUserName
                                                + CommonConstants.DashSignSeparator + roleName,
                                        operateUserName, OperationAction.Delete.value(),
                                        OperationModule.UserOrganizationRole.value()));
                    }
                }
                // 删除,附加原始角色 设置为不继承原始
                if (DimensionConstant.OriginalRoleDimensionValueId.equals(r.getDimensionValueId()) && userOrg != null) {
                    // UserOrganization old = CommonUtils.copyProperties(userOrg, new
                    // UserOrganization());
                    // 设置为不可继承原始角色
                    userOrg.setHasOriginalRole(CommonConstants.DEACTIVE_STATUS);
                    userOrganizationMapper.updateByPrimaryKey(userOrg);
                    // 添加日志
                    operationLogService
                            .updateDataAddLog(generateUpdateLogParams(OperateLogType.OperationLogUser.value(),
                                    orgName + CommonConstants.DashSignSeparator + operateUserName, operateUserName,
                                    OperationAction.Update.value(), OperationModule.UserOrganization.value()));
                }
            } else {
                // 机构在维度上的,设置可继承或者不可继承
                userRoleService.updateUserDimensionNonAccess(r);
            }
        }
        OperationResultDto operationResultDto = new OperationResultDto<>();
        operationResultDto.setResult(true);
        return operationResultDto;
    }

}