package cn.ey.biz.module.system.service.permission;

import cn.ey.biz.common.pojo.PageResult;
import cn.ey.biz.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.ey.biz.module.system.controller.admin.permission.vo.dataRole.DataRoleCodeBlockConfigVO;
import cn.ey.biz.module.system.controller.admin.permission.vo.dataRole.DataRoleVO;
import cn.ey.biz.module.system.controller.admin.permission.vo.role.RoleFunctionalReqVO;
import cn.ey.biz.module.system.controller.admin.permission.vo.role.RoleSimpleDataRespVO;
import cn.ey.biz.module.system.convert.permission.DataRoleConvert;
import cn.ey.biz.module.system.dal.dataobject.codeblock.CodeBlockDO;
import cn.ey.biz.module.system.dal.dataobject.permission.DataRoleDO;
import cn.ey.biz.module.system.dal.dataobject.permission.RoleCodeblockDO;
import cn.ey.biz.module.system.dal.dataobject.permission.UserDataRoleDO;
import cn.ey.biz.module.system.dal.dataobject.user.AdminUserDO;
import cn.ey.biz.module.system.dal.mapper.codeblock.CodeBlockMapper;
import cn.ey.biz.module.system.dal.mapper.permission.DataRoleMapper;
import cn.ey.biz.module.system.dal.mapper.permission.RoleCodeblockMapper;
import cn.ey.biz.module.system.dal.mapper.permission.UserDataRoleMapper;
import cn.ey.biz.module.system.dal.mapper.user.AdminUserMapper;
import cn.ey.biz.module.system.enums.permission.DataRoleConfigTypeEnum;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
@Slf4j
public class DataRoleServiceImpl implements DataRoleService {

    @Resource
    private DataRoleMapper dataRoleMapper;

    @Resource
    private UserDataRoleMapper userDataRoleMapper;

    @Resource
    private AdminUserMapper adminUserMapper;

    @Resource
    private RoleCodeblockMapper roleCodeblockMapper;

    @Resource
    private CodeBlockMapper codeBlockMapper;

    @Override
    @Transactional
    public Long createRole(DataRoleVO roleVO) {
        DataRoleDO doo = DataRoleConvert.INSTANCE.vo2Do(roleVO);
        dataRoleMapper.insert(doo);
        if (Objects.equals(roleVO.getType(), DataRoleConfigTypeEnum.CODE_BLOCK.getValue())) {
            insertRoleCodeblock(roleVO, doo.getId());
        }
        if (roleVO.getUserIds() != null && !roleVO.getUserIds().isEmpty()) {
            List<UserDataRoleDO> userDataRoleDOS = roleVO.getUserIds().stream().map(userid -> {
                UserDataRoleDO userDataRoleDO = new UserDataRoleDO();
                userDataRoleDO.setUserId(userid);
                userDataRoleDO.setRoleId(doo.getId());
                return userDataRoleDO;
            }).collect(Collectors.toList());

            userDataRoleMapper.insertBatch(userDataRoleDOS);
        }
        return doo.getId();
    }

    @Override
    @Transactional
    public void updateRole(DataRoleVO roleVO) {
        log.info("进入修改角色方法updateRole[2]");
        dataRoleMapper.updateById(DataRoleConvert.INSTANCE.vo2Do(roleVO));
        log.info("进入修改角色方法updateRole[3]");
        userDataRoleMapper.delete(new LambdaQueryWrapper<UserDataRoleDO>()
                .eq(UserDataRoleDO::getRoleId, roleVO.getId()));

        if (roleVO.getUserIds() != null && !roleVO.getUserIds().isEmpty()) {
            List<UserDataRoleDO> userDataRoleDOS = roleVO.getUserIds().stream().map(userid -> {
                UserDataRoleDO userDataRoleDO = new UserDataRoleDO();
                userDataRoleDO.setUserId(userid);
                userDataRoleDO.setRoleId(roleVO.getId());
                return userDataRoleDO;
            }).collect(Collectors.toList());
            userDataRoleMapper.insertBatch(userDataRoleDOS);
        }
        if (Objects.equals(roleVO.getType(), DataRoleConfigTypeEnum.CODE_BLOCK.getValue())) {
            //先删除后
            LambdaQueryWrapper<RoleCodeblockDO> deleteWrapper = Wrappers.<RoleCodeblockDO>lambdaQuery()
                    .eq(RoleCodeblockDO::getRoleId, roleVO.getId());
            roleCodeblockMapper.delete(deleteWrapper);
            //再保存
            insertRoleCodeblock(roleVO, roleVO.getId());
        }
    }

    public void insertRoleCodeblock(DataRoleVO roleVO, Long roleId) {
        List<String> codeBlocks = roleVO.getCodeBlocks();
        if (CollectionUtil.isEmpty(codeBlocks)) {
            return;
        }
        for (String co : codeBlocks) {
            RoleCodeblockDO roleCodeblockDo = new RoleCodeblockDO();
            roleCodeblockDo.setRoleId(roleId);
            roleCodeblockDo.setCodeBlock(co);
            roleCodeblockMapper.insert(roleCodeblockDo);
        }
    }

    @Override
    public void deleteRole(Long id) {
        dataRoleMapper.deleteById(id);

        userDataRoleMapper.delete(new LambdaQueryWrapper<UserDataRoleDO>()
                .eq(UserDataRoleDO::getRoleId, id));

        roleCodeblockMapper.delete(new LambdaQueryWrapper<RoleCodeblockDO>()
                .eq(RoleCodeblockDO::getRoleId, id));
    }

    @Override
    public PageResult<DataRoleVO> getRolePage(DataRoleVO roleVO) {
        LambdaQueryWrapper<DataRoleDO> query = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(roleVO.getSl())) {
            query.eq(DataRoleDO::getSl, roleVO.getSl());
        }

        if (StringUtils.isNotBlank(roleVO.getName())) {
            query.eq(DataRoleDO::getName, roleVO.getName());
        }

        if (StringUtils.isNotBlank(roleVO.getMr())) {
            query.eq(DataRoleDO::getMr, roleVO.getMr());
        }

        if (StringUtils.isNotBlank(roleVO.getApp())) {
            query.eq(DataRoleDO::getApp, roleVO.getApp());
        }

        PageResult<DataRoleVO> pageResult = DataRoleConvert.INSTANCE.do2VoPage(dataRoleMapper.selectPage(roleVO, query));
        pageResult.setList(pageResult.getList().stream().peek(item -> {
            List<Long> userIds = userDataRoleMapper.selectList(new LambdaQueryWrapper<UserDataRoleDO>()
                    .eq(UserDataRoleDO::getRoleId, item.getId())).stream().map(UserDataRoleDO::getUserId).collect(Collectors.toList());
            item.setUserIds(userIds);
        }).collect(Collectors.toList()));

        List<DataRoleVO> dataRoleVOLi = pageResult.getList();
        for (DataRoleVO data : dataRoleVOLi) {
            List<RoleCodeblockDO> roleCodeBlockDOs = roleCodeblockMapper
                    .selectList(new LambdaQueryWrapper<RoleCodeblockDO>()
                            .eq(RoleCodeblockDO::getRoleId, data.getId()));
            List<String> ids = roleCodeBlockDOs.stream().map(RoleCodeblockDO::getCodeBlock).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(ids)) {
                List<CodeBlockDO> codeBlockDOS = codeBlockMapper
                        .selectList(new LambdaQueryWrapper<CodeBlockDO>()
                                .in(CodeBlockDO::getCodeBlockCode, ids));

                List<DataRoleCodeBlockConfigVO> codeBlockToVo = DataRoleConvert.INSTANCE.codeBlockToVo(codeBlockDOS);
                data.setCodeBlocksObject(codeBlockToVo);
            }
        }
        return pageResult;
    }

    @Override
    public List<DataRoleVO> getRoleListByUserId(Long id) {
        AdminUserDO user = adminUserMapper.selectById(id);

        LambdaQueryWrapper<DataRoleDO> wrapper = new LambdaQueryWrapper<DataRoleDO>()
                .and(a -> a.eq(DataRoleDO::getSl, "").or().eq(DataRoleDO::getSl, user.getServiceLine()))
                .and(a -> a.eq(DataRoleDO::getMr, "").or().eq(DataRoleDO::getMr, user.getMgmtRegion()));

        return DataRoleConvert.INSTANCE.dos2Vos(dataRoleMapper.selectList(wrapper));
    }

    @Override
    public List<DataRoleVO> getAllRoleList() {
        return DataRoleConvert.INSTANCE.dos2Vos(dataRoleMapper.selectList());
    }

    @Override
    public List<AdminUserDO> getUsersByDataRoleId(Long dataRoleId) {
        List<Long> userIds = userDataRoleMapper.selectList(new LambdaQueryWrapperX<UserDataRoleDO>()
                        .eq(UserDataRoleDO::getRoleId, dataRoleId)).stream().map(UserDataRoleDO::getUserId)
                .collect(Collectors.toList());
        if (userIds.isEmpty()) {
            return new ArrayList<>();
        }
        return adminUserMapper.selectList(new LambdaQueryWrapperX<AdminUserDO>().in(AdminUserDO::getId, userIds));
    }

    @Override
    public List<AdminUserDO> getUsersByDataRoleCode(String code) {
        DataRoleDO roleDO = dataRoleMapper.selectOne(new LambdaQueryWrapperX<DataRoleDO>()
                .eq(DataRoleDO::getCode, code));

        if (Objects.isNull(roleDO)) {
            return new ArrayList<>();
        }

        List<Long> userIds = userDataRoleMapper.selectList(new LambdaQueryWrapperX<UserDataRoleDO>()
                        .eq(UserDataRoleDO::getRoleId, roleDO.getId())).stream().map(UserDataRoleDO::getUserId)
                .collect(Collectors.toList());
        if (userIds.isEmpty()) {
            return new ArrayList<>();
        }
        return adminUserMapper.selectList(new LambdaQueryWrapperX<AdminUserDO>().in(AdminUserDO::getId, userIds));
    }


    @Override
    public List<RoleSimpleDataRespVO> getDataRoles(RoleFunctionalReqVO reqVO) {
        return dataRoleMapper.selectDataRoles(reqVO);
    }

    @Override
    public String getMaxRoleCodeByAppAndClass(String appCode) {
        return IdUtil.fastSimpleUUID();
    }
}
