package com.hotwj.platform.resourceManagement.companyPermissionGrant.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotwj.platform.resourceManagement.companyPermissionGrant.domain.HotCompanyPermissionGrant;
import com.hotwj.platform.resourceManagement.companyPermissionGrant.domain.bo.HotCompanyPermissionGrantBo;
import com.hotwj.platform.resourceManagement.companyPermissionGrant.domain.vo.HotCompanyPermissionGrantVo;
import com.hotwj.platform.resourceManagement.companyPermissionGrant.mapper.HotCompanyPermissionGrantMapper;
import com.hotwj.platform.resourceManagement.companyPermissionGrant.service.IHotCompanyPermissionGrantService;
import com.hotwj.platform.resourceManagement.companySafetyManager.domain.HotCompanySafetyManager;
import com.hotwj.platform.resourceManagement.companySafetyManager.mapper.HotCompanySafetyManagerMapper;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysMenu;
import org.dromara.system.mapper.SysMenuMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class HotCompanyPermissionGrantServiceImpl implements IHotCompanyPermissionGrantService {

    private final HotCompanyPermissionGrantMapper baseMapper;
    private final HotCompanySafetyManagerMapper safetyManagerMapper;
    private final SysMenuMapper sysMenuMapper;

    @Override
    public HotCompanyPermissionGrantVo queryById(Long id) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        Long companyId = loginUser.getCompanyId();
        getCurrentOperator(companyId, loginUser.getUserId());
        return baseMapper.selectVoOne(Wrappers.<HotCompanyPermissionGrant>lambdaQuery()
                .eq(HotCompanyPermissionGrant::getId, id)
                .eq(HotCompanyPermissionGrant::getCompanyId, companyId)
                .eq(HotCompanyPermissionGrant::getIsDeleted, 0L));
    }

    @Override
    public TableDataInfo<HotCompanyPermissionGrantVo> queryPageList(HotCompanyPermissionGrantBo bo, PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        getCurrentOperator(loginUser.getCompanyId(), loginUser.getUserId());
        bo.setCompanyId(loginUser.getCompanyId());
        LambdaQueryWrapper<HotCompanyPermissionGrant> lqw = buildQueryWrapper(bo);
        Page<HotCompanyPermissionGrantVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(HotCompanyPermissionGrantBo bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        Long companyId = bo.getCompanyId() == null ? loginUser.getCompanyId() : bo.getCompanyId();
        if (companyId == null) {
            throw new ServiceException("公司ID不能为空");
        }
        HotCompanySafetyManager grantor = getCurrentOperator(companyId, loginUser.getUserId());
        HotCompanySafetyManager grantee = getGrantee(companyId, bo.getGranteeManagerId());
        checkGrantRelation(grantor, grantee);
        Long menuId = checkPermissionCode(bo.getPermissionCode(), bo.getMenuId());
        checkTimeRange(bo.getEffectiveTime(), bo.getExpireTime());
        resetGranteePermissions(companyId, grantee.getId(), grantee.getUserId(), grantor.getId(), grantor.getUserId(), null);

        HotCompanyPermissionGrant entity = new HotCompanyPermissionGrant();
        entity.setCompanyId(companyId);
        entity.setGranteeManagerId(grantee.getId());
        entity.setGranteeUserId(grantee.getUserId());
        entity.setPermissionCode(bo.getPermissionCode());
        entity.setMenuId(menuId);
        entity.setStatus(bo.getStatus() == null ? 1L : bo.getStatus());
        entity.setEffectiveTime(bo.getEffectiveTime());
        entity.setExpireTime(bo.getExpireTime());
        entity.setRemark(bo.getRemark());
        entity.setGrantorManagerId(grantor.getId());
        entity.setGrantorUserId(grantor.getUserId());
        entity.setIsDeleted(0L);
        boolean flag = baseMapper.insert(entity) > 0;
        if (flag) {
            bo.setId(entity.getId());
        }
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(HotCompanyPermissionGrantBo bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        HotCompanyPermissionGrant old = baseMapper.selectById(bo.getId());
        if (old == null || Long.valueOf(1L).equals(old.getIsDeleted())) {
            throw new ServiceException("授权记录不存在");
        }
        HotCompanySafetyManager grantor = getCurrentOperator(old.getCompanyId(), loginUser.getUserId());
        checkTimeRange(bo.getEffectiveTime(), bo.getExpireTime());
        HotCompanySafetyManager grantee = bo.getGranteeManagerId() == null
                ? getGrantee(old.getCompanyId(), old.getGranteeManagerId())
                : getGrantee(old.getCompanyId(), bo.getGranteeManagerId());
        checkGrantRelation(grantor, grantee);
        resetGranteePermissions(old.getCompanyId(), grantee.getId(), grantee.getUserId(), grantor.getId(), grantor.getUserId(), old.getId());

        HotCompanyPermissionGrant update = MapstructUtils.convert(bo, HotCompanyPermissionGrant.class);
        String permissionCode = StringUtils.isNotBlank(bo.getPermissionCode()) ? bo.getPermissionCode() : old.getPermissionCode();
        Long menuId = checkPermissionCode(permissionCode, bo.getMenuId());
        update.setPermissionCode(permissionCode);
        update.setMenuId(menuId);
        update.setGranteeManagerId(grantee.getId());
        update.setGranteeUserId(grantee.getUserId());
        update.setGrantorManagerId(grantor.getId());
        update.setGrantorUserId(grantor.getUserId());
        update.setCompanyId(old.getCompanyId());
        update.setStatus(bo.getStatus() == null ? 1L : bo.getStatus());
        update.setIsDeleted(0L);
        return baseMapper.updateById(update) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (CollUtil.isEmpty(ids)) {
            return false;
        }
        LoginUser loginUser = LoginHelper.getLoginUser();
        HotCompanySafetyManager grantor = getCurrentOperator(loginUser.getCompanyId(), loginUser.getUserId());
        LambdaUpdateWrapper<HotCompanyPermissionGrant> luw = Wrappers.lambdaUpdate();
        luw.in(HotCompanyPermissionGrant::getId, ids)
                .eq(HotCompanyPermissionGrant::getCompanyId, loginUser.getCompanyId())
                .eq(HotCompanyPermissionGrant::getIsDeleted, 0L)
                .set(HotCompanyPermissionGrant::getStatus, 0L)
                .set(HotCompanyPermissionGrant::getIsDeleted, 1L)
                .set(HotCompanyPermissionGrant::getGrantorManagerId, grantor.getId())
                .set(HotCompanyPermissionGrant::getGrantorUserId, grantor.getUserId());
        return baseMapper.update(null, luw) > 0;
    }

    @Override
    public Set<String> selectActivePermissionCodes(Long companyId, Long granteeUserId) {
        Date now = new Date();
        List<Object> objs = baseMapper.selectObjs(Wrappers.<HotCompanyPermissionGrant>lambdaQuery()
                .select(HotCompanyPermissionGrant::getPermissionCode)
                .eq(HotCompanyPermissionGrant::getCompanyId, companyId)
                .eq(HotCompanyPermissionGrant::getGranteeUserId, granteeUserId)
                .eq(HotCompanyPermissionGrant::getStatus, 1L)
                .eq(HotCompanyPermissionGrant::getIsDeleted, 0L)
                .and(w -> w.isNull(HotCompanyPermissionGrant::getEffectiveTime)
                        .or()
                        .le(HotCompanyPermissionGrant::getEffectiveTime, now))
                .and(w -> w.isNull(HotCompanyPermissionGrant::getExpireTime)
                        .or()
                        .ge(HotCompanyPermissionGrant::getExpireTime, now)));
        return objs.stream()
                .map(String::valueOf)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
    }

    private LambdaQueryWrapper<HotCompanyPermissionGrant> buildQueryWrapper(HotCompanyPermissionGrantBo bo) {
        LambdaQueryWrapper<HotCompanyPermissionGrant> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getCompanyId() != null, HotCompanyPermissionGrant::getCompanyId, bo.getCompanyId());
        lqw.eq(bo.getGrantorManagerId() != null, HotCompanyPermissionGrant::getGrantorManagerId, bo.getGrantorManagerId());
        lqw.eq(bo.getGrantorUserId() != null, HotCompanyPermissionGrant::getGrantorUserId, bo.getGrantorUserId());
        lqw.eq(bo.getGranteeManagerId() != null, HotCompanyPermissionGrant::getGranteeManagerId, bo.getGranteeManagerId());
        lqw.eq(bo.getGranteeUserId() != null, HotCompanyPermissionGrant::getGranteeUserId, bo.getGranteeUserId());
        lqw.eq(StringUtils.isNotBlank(bo.getPermissionCode()), HotCompanyPermissionGrant::getPermissionCode, bo.getPermissionCode());
        lqw.eq(bo.getStatus() != null, HotCompanyPermissionGrant::getStatus, bo.getStatus());
        lqw.eq(HotCompanyPermissionGrant::getIsDeleted, 0L);
        lqw.orderByDesc(HotCompanyPermissionGrant::getCreateTime);
        return lqw;
    }

    private HotCompanySafetyManager getCurrentOperator(Long companyId, Long userId) {
        HotCompanySafetyManager manager = safetyManagerMapper.selectOne(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .eq(HotCompanySafetyManager::getCompanyId, companyId)
                .eq(HotCompanySafetyManager::getUserId, userId)
                .eq(HotCompanySafetyManager::getStatus, 1L)
                .eq(HotCompanySafetyManager::getIsResigned, 0L)
                .eq(HotCompanySafetyManager::getIsDeleted, 0L));
        if (manager == null) {
            throw new ServiceException("仅企业安全管理人员可以分发权限");
        }
        return manager;
    }

    private HotCompanySafetyManager getGrantee(Long companyId, Long granteeManagerId) {
        HotCompanySafetyManager manager = safetyManagerMapper.selectOne(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .eq(HotCompanySafetyManager::getId, granteeManagerId)
                .eq(HotCompanySafetyManager::getCompanyId, companyId)
                .eq(HotCompanySafetyManager::getStatus, 1L)
                .eq(HotCompanySafetyManager::getIsResigned, 0L)
                .eq(HotCompanySafetyManager::getIsDeleted, 0L));
        if (manager == null) {
            throw new ServiceException("被授权人不存在或状态不可用");
        }
        if (Long.valueOf(1L).equals(manager.getCompanyHead())) {
            throw new ServiceException("不允许给企业负责人分配权限");
        }
        return manager;
    }

    private void checkGrantRelation(HotCompanySafetyManager grantor, HotCompanySafetyManager grantee) {
        if (grantor != null && grantee != null && grantor.getId() != null && grantor.getId().equals(grantee.getId())) {
            throw new ServiceException("不允许给自己分配权限");
        }
        if (isCompanyHead(grantee)) {
            throw new ServiceException("不允许给企业负责人分配权限");
        }
        if (!isCompanyHead(grantor) && isCompanyHead(grantee)) {
            throw new ServiceException("企业安全管理人员不可以给企业负责人分配权限");
        }
    }

    private boolean isCompanyHead(HotCompanySafetyManager manager) {
        return manager != null && Long.valueOf(1L).equals(manager.getCompanyHead());
    }

    private void resetGranteePermissions(Long companyId, Long granteeManagerId, Long granteeUserId,
                                         Long grantorManagerId, Long grantorUserId, Long excludeId) {
        LambdaUpdateWrapper<HotCompanyPermissionGrant> luw = Wrappers.lambdaUpdate();
        luw.eq(HotCompanyPermissionGrant::getCompanyId, companyId)
                .eq(HotCompanyPermissionGrant::getGranteeManagerId, granteeManagerId)
                .eq(HotCompanyPermissionGrant::getGranteeUserId, granteeUserId)
                .eq(HotCompanyPermissionGrant::getIsDeleted, 0L)
                .ne(excludeId != null, HotCompanyPermissionGrant::getId, excludeId)
                .set(HotCompanyPermissionGrant::getStatus, 0L)
                .set(HotCompanyPermissionGrant::getIsDeleted, 1L)
                .set(HotCompanyPermissionGrant::getGrantorManagerId, grantorManagerId)
                .set(HotCompanyPermissionGrant::getGrantorUserId, grantorUserId);
        baseMapper.update(null, luw);
    }

    private Long checkPermissionCode(String permissionCode, Long menuId) {
        SysMenu menu = sysMenuMapper.selectOne(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getPerms, permissionCode)
                .eq(SysMenu::getStatus, "0")
                .last("limit 1"));
        if (menu == null) {
            throw new ServiceException("权限标识不存在或菜单已停用");
        }
        if (menuId != null && !menuId.equals(menu.getMenuId())) {
            throw new ServiceException("menuId 与 permissionCode 不匹配");
        }
        return menu.getMenuId();
    }

    private void checkTimeRange(Date effectiveTime, Date expireTime) {
        if (effectiveTime != null && expireTime != null && effectiveTime.after(expireTime)) {
            throw new ServiceException("失效时间不能早于生效时间");
        }
    }
}
