package com.reyun.saas.mob.user.service.impl;

import com.reyun.saas.common.constants.RoleEnumType;
import com.reyun.saas.common.model.Constant;
import com.reyun.saas.mob.user.dao.AppAuthMapper;
import com.reyun.saas.mob.user.dao.AppMapper;
import com.reyun.saas.mob.user.dao.ChannelMapper;
import com.reyun.saas.mob.user.dao.UserMapper;
import com.reyun.saas.mob.user.domain.App;
import com.reyun.saas.mob.user.domain.AppAuth;
import com.reyun.saas.mob.user.domain.Channel;
import com.reyun.saas.mob.user.domain.User;
import com.reyun.saas.mob.user.dto.user.UserOutpDTO;
import com.reyun.saas.mob.user.service.AuthService;
import com.reyun.saas.mob.util.RoleUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author: hanzepeng
 * @Date: 2021/09/22/16:33
 * @Description: 权限业务层
 */

@Slf4j
@Service
@Transactional
public class AuthServiceImpl implements AuthService {


    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AppMapper appMapper;


    @Autowired
    private AppAuthMapper appAuthMapper;

    @Resource
    private ChannelMapper channelMapper;

    /**
     * 查询该用户的app
     * @param user 目标用户
     * @return
     */
    @Override
    public List<App> getAppByUser(User user) {

        return getAppByUserAndOs(user,null,null);
    }

    /**
     * 查询该用户的app  包括用户已经删除的qpp
     * @param user 目标用户
     * @return
     */
    @Override
    public List<App> getAppByUserIncludeDel(User user) {
        List<App> apps = new ArrayList<>();
        if (RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory()) ||
                RoleEnumType.MANAGER.getKey().equals(user.getRoleCategory())) {
            //主账号  管理员
            Long rootId = RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory())?user.getId():user.getRootParent();

            Example example = new Example(App.class);
            example.and().andEqualTo("rootParent", rootId);
//            example.and().andEqualTo("delFlag", false);
            apps = appMapper.selectByExample(example);

        } else  {
            //其他账号
            Example appAuthExample = new Example(AppAuth.class);
            appAuthExample.and().andEqualTo("userId",user.getId());
            appAuthExample.and().andEqualTo("status",true);
            List<AppAuth> auths = appAuthMapper.selectByExample(appAuthExample);
            if (!CollectionUtils.isEmpty(auths)){
                List<Long> appids = new LinkedList<>();
                auths.forEach(v -> {
                    appids.add(v.getAppId());
                });

                Example example = new Example(App.class);
                example.and().andIn("id",appids );
//                example.and().andEqualTo("delFlag", false);
                apps = appMapper.selectByExample(example);
            }
        }

        return apps;
    }


    @Override
    public Integer getRootUserAppNumByUser(User user) {

        int result = 0;
        if (user == null) {
            return result;
        }
        Long rootId = RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory())?user.getId():user.getRootParent();
        Example example = new Example(App.class);
        example.and().andEqualTo("rootParent",rootId);
        example.and().andEqualTo("delFlag",false);
        result = appMapper.selectCountByExample(example);
        return result;

    }


    /**
     * 根据用户查询主用户
     * @param user 用户
     * @return 主用户
     */
    public User getRootParent(User user) {
        if (RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory())) {
            //主账号
            return user;
        }

        Example example = new Example(User.class);
        example.and().andEqualTo("id", user.getRootParent());
        example.and().andEqualTo("delFlag",false);
        //查询主账号
        return userMapper.selectOneByExample(example);
    }



    /**
     * todo 校验当前登陆用户是否可以操作目标用户
     * @param loginUser 当前登录用户
     * @param targetUser 目标用户
     * @return 如果权限不足返回false
     */
    public boolean checkloginUserAuth(User loginUser,User targetUser){

        if(loginUser.getId().equals(targetUser.getId())){
            return true;
        }

        if (RoleEnumType.SUPER_USER.getKey().equals(loginUser.getRoleCategory())) {
            //主用户
            if (!targetUser.getRootParent().equals(loginUser.getId())) {
                return false;
            }
        }else if(RoleEnumType.MANAGER.getKey().equals(loginUser.getRoleCategory())){
            //管理员
            if(!targetUser.getRootParent().equals(loginUser.getRootParent())){
                return false;
            }
        }else if(RoleEnumType.SUB_APP_MANAGER.getKey().equals(loginUser.getRoleCategory())){
            //子应用管理员
            if(!targetUser.getLeaderParent().equals(loginUser.getId())){
                return false;
            }
        }else{
            //其他
            return false;
        }

        return true;
    }
    @Override
    public boolean checkloginUserAuth(Long loginUserId,String email){
        User loginUser = userMapper.selectByPrimaryKey(loginUserId);
        Example example = new Example(User.class);
        example.and().andEqualTo("username",email);
        User targetUser = userMapper.selectOneByExample(example);
        if(targetUser==null){
            return false;
        }
        return this.checkloginUserAuth(loginUser,targetUser);
    }
    @Override
    public boolean checkloginUserAuth(Long loginUserId,Long targetUserId){
        User loginUser = userMapper.selectByPrimaryKey(loginUserId);
        User targetUser = userMapper.selectByPrimaryKey(targetUserId);
        if(targetUser==null){
            return false;
        }
        return this.checkloginUserAuth(loginUser,targetUser);
    }
    /**
     * todo 校验当前登陆用户是否可以操作目标app
     * 校验逻辑:
     *   主账号/管理员 用appid查询出app  拿主账号id和app的root_parent字段比较  比较通过为有权限
     *   其他角色  以userid 和 appid 为条件去app_auth表中查询数据  查到数据为有权限
     *
     * @param user 目标用户
     * @param appId 目标app
     * @return 是否可以操作 true为可以操作  false为无法操作
     */
    @Override
    public boolean checkUserAppAuth(User user, Long appId) {

        if(user == null || appId == null){
            return false;
        }

        if(RoleUtil.isSuperUserOrManager(user)){
            //主账号或者管理员
            Long rootId = RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory())?user.getId():user.getRootParent();
            App app = appMapper.selectByPrimaryKey(appId);
            if (app == null) {
                return false;
            }
            if (!app.getRootParent().equals(rootId)) {
                return false;
            }
        }else{
            //其他账号
            Example example = new Example(AppAuth.class);
            example.and().andEqualTo("userId",user.getId());
            example.and().andEqualTo("appId",appId);
            example.and().andEqualTo("status",1);
            AppAuth appAuth = appAuthMapper.selectOneByExample(example);
            if (appAuth == null) {
                return false;
            }
        }
        return true;
    }


    /**
     * todo 校验当前登陆用户是否可以操作目标app
     * 校验逻辑:
     *   主账号/管理员 用appkey查询出app  拿主账号id和app的root_parent字段比较  比较通过为有权限
     *   其他角色  用appkey查询出app  再用userid 和 appid 为条件去app_auth表中查询数据  查到数据为有权限
     *
     * @param user 目标用户
     * @param appkey 目标app
     * @return 是否可以操作 true为可以操作  false为无法操作
     */
    @Override
    public boolean checkUserAppAuth(User user, String appkey) {
        if(user == null || appkey == null){
            return false;
        }

        if(RoleUtil.isSuperUserOrManager(user)){
            //主账号或者管理员
            Long rootId = RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory())?user.getId():user.getRootParent();

            Example example = new Example(App.class);
            example.and().andEqualTo("appkey",appkey);
//            example.and().andEqualTo("delFlag",false);
            App app = appMapper.selectOneByExample(example);
            if (app == null) {
                return false;
            }
            if (!app.getRootParent().equals(rootId)) {
                return false;
            }
        }else{
            //其他账号
            Example example = new Example(App.class);
            example.and().andEqualTo("appkey",appkey);
            example.and().andEqualTo("delFlag",false);
            App app = appMapper.selectOneByExample(example);//查询app
            if (app == null) {
                return false;
            }

            Example appAuthExample = new Example(AppAuth.class);
            appAuthExample.and().andEqualTo("userId",user.getId());
            appAuthExample.and().andEqualTo("appId",app.getId());
            appAuthExample.and().andEqualTo("status",1);
            AppAuth appAuth = appAuthMapper.selectOneByExample(appAuthExample);//查询app权限
            if (appAuth == null) {
                return false;
            }
        }
        return true;
    }


    /**
     * todo 过滤当前登陆用户没有权限的app
     * 逻辑:
     *   主要过滤逻辑是操作查询app的条件  该方法不会返回空
     *   主账号/管理员:  app表查询条件 where id in #{appids} and root_parent = #{rootParent} and del_flag is false
     *   其他角色:  app_auth表查询条件 where  user_id = #{userId} and app_id in (#{appids}) and status = 1  之后根据查出来的app权限再去查app表
     *
     * @param user 目标用户
     * @param appIds 待过滤app
     * @return 过滤后用户有权限的app集合
     */
    @Override
    public List<App> filterUserAppAuthByAppId(User user, List<Long> appIds) {

        List<App> result = new ArrayList<>();
        if(user == null || (appIds == null || appIds.size() == 0 )){
            return result;
        }

        if (RoleUtil.isSuperUserOrManager(user)) {
            //主账号或者管理员
            Long rootId = RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory())?user.getId():user.getRootParent();
            Example example = new Example(App.class);
            example.and().andIn("id",appIds);
            example.and().andEqualTo("rootParent",rootId);
            example.and().andEqualTo("delFlag",false);
            result = appMapper.selectByExample(example);
        }else{
            //其他账号
            Example appAuthExample = new Example(AppAuth.class);
            appAuthExample.and().andEqualTo("userId",user.getId());
            appAuthExample.and().andIn("appId",appIds);
            appAuthExample.and().andEqualTo("status",1);
            List<AppAuth> appAuths = appAuthMapper.selectByExample(appAuthExample);
            if (!CollectionUtils.isEmpty(appAuths)) {
                List<Long> userAppids = new ArrayList<>();
                appAuths.forEach(v -> {
                    userAppids.add(v.getAppId());
                });

                Example appExample = new Example(App.class);
                appExample.and().andIn("id",userAppids);
                appExample.and().andEqualTo("delFlag",false);
                result = appMapper.selectByExample(appExample);
            }
        }

        return result;
    }

    /**
     * todo 过滤当前登陆用户没有权限的app
     * 逻辑:
     *   主要过滤逻辑是操作查询app的条件  该方法不会返回空
     *   主账号/管理员:  app表查询条件 where root_parent = #{rootParent} and appkey in (#{appkeys}) and del_flag is false
     *   其他角色:  app_auth表查询条件 where  user_id = #{userId} and status = 1 查询出来权限之后封装appids
     *            再去app表中查询app where id in (#{appAuth.appids}) and appkey in (appkeys) and del_flag is false
     *
     * @param user 目标用户
     * @param appkeys 待过滤app
     * @return 过滤后用户有权限的app集合
     */
    @Override
    public List<App> filterUserAppAuthByAppkey(User user, List<String> appkeys) {

        List<App> result = new ArrayList<>();
        if(user == null || (appkeys == null || appkeys.size() == 0 )){
            return result;
        }

        if (RoleUtil.isSuperUserOrManager(user)) {
            //主账号或者管理员
            Long rootId = RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory())?user.getId():user.getRootParent();
            Example example = new Example(App.class);
            example.and().andEqualTo("rootParent",rootId);
            example.and().andIn("appkey",appkeys);
            example.and().andEqualTo("delFlag",false);
            result = appMapper.selectByExample(example);
        }else{
            //其他账号
            Example appAuthExample = new Example(AppAuth.class);
            appAuthExample.and().andEqualTo("userId",user.getId());
            appAuthExample.and().andEqualTo("status",1);
            List<AppAuth> appAuths = appAuthMapper.selectByExample(appAuthExample);
            if (!CollectionUtils.isEmpty(appAuths)) {
                List<Long> userAppids = new ArrayList<>();
                appAuths.forEach(v -> {
                    userAppids.add(v.getAppId());
                });

                Example appExample = new Example(App.class);
                appExample.and().andIn("id",userAppids);
                appExample.and().andIn("appkey",appkeys);
                appExample.and().andEqualTo("delFlag",false);
                result = appMapper.selectByExample(appExample);
            }
        }

        return result;
    }


    /**
     * 校验用户是否拥有产品权限
     * @param userOutpDTO 目标用户
     * @return true为拥有权限  false为没有权限
     */
    @Override
    public boolean isPossessAppAuth(UserOutpDTO userOutpDTO) {
        if (userOutpDTO == null) {
            return false;
        }
        if(RoleEnumType.SUPER_USER.getKey().equals(userOutpDTO.getRoleCategory())
            || RoleEnumType.MANAGER.getKey().equals(userOutpDTO.getRoleCategory())){
            //主账号或者管理员
            return true;
        }else if(RoleEnumType.SUB_APP_MANAGER.getKey().equals(userOutpDTO.getRoleCategory())){
            //子应用管理员
            if(userOutpDTO.getAuthConfig()){
                //分配了app权限
                return true;
            }else{
                //没有分配app权限   如果没有分配app权限再判断是否拥有创建app的权限  如果有允许登录
                return userOutpDTO.getIsCreateApp();
            }
        } else{
            //其他角色
            return userOutpDTO.getAuthConfig();
        }
    }

    /**
     * 校验用户渠道权限
     * 逻辑 :主账号.管理员.子应用管理员 先查出目标渠道  再校验渠道对应的app
     * @param loginUser 目标用户
     * @param channelId 目标权限
     */
    @Override
    public boolean checkUserChannelAuth(User loginUser, Long channelId) {
        if(loginUser == null || channelId == null){
            return false;
        }
        if (RoleUtil.isSuperUserOrManager(loginUser) || RoleUtil.isSubAppManager(loginUser)) {
            //主账号 管理员 子应用管理员
            Channel channel = channelMapper.selectByPrimaryKey(channelId);
            if (channel == null) {
                return false;
            }
            return checkUserAppAuth(loginUser,channel.getAppkey());
        }else{
            //其他角色
        }
        return true;
    }

    @Override
    public List<Channel> filterUserChannelAuthByChannelId(User user, List<Long> channelIds) {
        List<Channel> channels = new ArrayList<>();
        if(user == null || CollectionUtils.isEmpty(channelIds)){
            return channels;
        }
        if(RoleUtil.isSuperUserOrManager(user) || RoleUtil.isSubAppManager(user)){
            //主账号  管理员   子应用管理员
            List<App> apps = getAppByUser(user);
            if(CollectionUtils.isEmpty(apps)){
                return channels;
            }
            List<String> appkeys = apps.stream().map(App::getAppkey).collect(Collectors.toList());
            Example example = new Example(Channel.class);
            example.and().andIn("id",channelIds);
            example.and().andIn("appkey",appkeys);
            example.and().andEqualTo("delFlag",false);
            channels = channelMapper.selectByExample(example);
        }else{
            //其他角色


        }
        return channels;
    }


    /**
     * 追加app权限
     * @param user 用户
     * @param app 要追加的app权限
     * @return
     */
    @Override
    public int appendAuth(User user, App app) {

        AppAuth appAuth = new AppAuth();
        appAuth.setAppId(app.getId());
        appAuth.setStatus(1);
        appAuth.setUserId(user.getId());
        appAuth.setCreateTime(new Date());
        appAuth.setCreateUser(user.getId());
        appAuth.setRoleCategory(user.getRoleCategory());
        return appAuthMapper.insertSelective(appAuth);
    }

    /**
     * 根据用户查询app权限
     * @param user 目标用户
     * @return 权限
     */
    @Override
    public List<AppAuth> findAppAuthByUser(User user) {

        Example example = new Example(AppAuth.class);
        example.and().andEqualTo("userId",user.getId());
        return appAuthMapper.selectByExample(example);
    }

    /**
     * 删除appauth表中的app权限
     * @param appId appid
     * @return 影响行数
     */
    @Override
    public int deleteAppAuth(Long appId) {

        //todo 后续如果有其他权限留意这里
        return  appAuthMapper.deleteByAppid(appId);
    }

    @Override
    public List<Long> getChildUserIdsAndOwn(Long userId){
        User user = userMapper.selectByPrimaryKey(userId);
        List<Long> ids = null;
        if (RoleUtil.isSuperUserOrManager(user)) {
            ids = userMapper.selectBySuperUser(user.getId());
        }else{
            ids = userMapper.selectBySubManager(user.getId());
        }
        return ids;
    }

    @Override
    public List<App> getAppByUserAndOs(User user, String os,Boolean disable) {
        List<App> apps = new ArrayList<>();
        if (RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory()) ||
                RoleEnumType.MANAGER.getKey().equals(user.getRoleCategory())) {
            //主账号  管理员
            Long rootId = RoleEnumType.SUPER_USER.getKey().equals(user.getRoleCategory())?user.getId():user.getRootParent();

            Example example = new Example(App.class);
            example.and().andEqualTo("rootParent", rootId);
            example.and().andEqualTo("delFlag", false);
            if(!StringUtils.isEmpty(os)){
                os = os.equals("1")?Constant.OS_IOS:Constant.OS_ANDROID;
                example.and().andEqualTo("os", os);
            }
            if(null!=disable){
                example.and().andEqualTo("disableFlag", disable);
            }
            apps = appMapper.selectByExample(example);

        } else  {
            //其他账号
            Example appAuthExample = new Example(AppAuth.class);
            appAuthExample.and().andEqualTo("userId",user.getId());
            appAuthExample.and().andEqualTo("status",true);
            List<AppAuth> auths = appAuthMapper.selectByExample(appAuthExample);
            if (!CollectionUtils.isEmpty(auths)){
                List<Long> appids = new LinkedList<>();
                auths.forEach(v -> {
                    appids.add(v.getAppId());
                });

                Example example = new Example(App.class);
                example.and().andIn("id",appids );
                example.and().andEqualTo("delFlag", false);
                if(!StringUtils.isEmpty(os)){
                    os = os.equals("1")?Constant.OS_IOS:Constant.OS_ANDROID;
                    example.and().andEqualTo("os", os);
                }
                if(null!=disable){
                    example.and().andEqualTo("disableFlag", disable);
                }
                apps = appMapper.selectByExample(example);
            }
        }

        return apps;
    }

    @Override
    public List<Channel> getChannelByUserAndOs(User loginUser, String os,Boolean active) {
        os=os.equals("1")?Constant.OS_IOS:Constant.OS_ANDROID;

        List<Channel> result = new ArrayList<>();

        if(RoleUtil.isSuperUserOrManager(loginUser) || RoleUtil.isSubAppManager(loginUser)){
            //主账号 管理员  子应用管理员 根据app权限查询渠道
            List<App> appByUserAndOs = getAppByUserAndOs(loginUser, os, null);
            if (CollectionUtils.isEmpty(appByUserAndOs)) {
                return result;
            }
            List<String> appkeys = appByUserAndOs.stream().map(App::getAppkey).collect(Collectors.toList());

           return channelMapper.findByappkeysAndActive(appkeys,active);

        }else{
            //其他角色

        }

        return result;
    }

}
