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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotwj.platform.resourceManagement.company.domain.SysCompanyRole;
import com.hotwj.platform.resourceManagement.company.domain.SysCompanyRoleMenu;
import com.hotwj.platform.resourceManagement.company.domain.bo.SysCompanyRoleBo;
import com.hotwj.platform.resourceManagement.company.domain.vo.SysCompanyRoleVo;
import com.hotwj.platform.resourceManagement.company.mapper.SysCompanyRoleMapper;
import com.hotwj.platform.resourceManagement.company.mapper.SysCompanyRoleMenuMapper;
import com.hotwj.platform.resourceManagement.company.service.ISysCompanyRoleService;
import com.hotwj.platform.resourceManagement.companySafetyManager.domain.HotCompanySafetyManager;
import com.hotwj.platform.resourceManagement.companySafetyManager.mapper.HotCompanySafetyManagerMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.bo.SysMenuBo;
import org.dromara.system.domain.vo.SysMenuVo;
import org.dromara.system.service.ISysMenuService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

import static com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService.ENTERPRISE_PORT;

@Slf4j
@RequiredArgsConstructor
@Service
public class SysCompanyRoleServiceImpl implements ISysCompanyRoleService {

    private final SysCompanyRoleMapper baseMapper;
    private final SysCompanyRoleMenuMapper roleMenuMapper;
    private final HotCompanySafetyManagerMapper safetyManagerMapper;
    private final ISysMenuService menuService;

    @Override
    public SysCompanyRoleVo queryById(Long id) {
        SysCompanyRoleVo vo = baseMapper.selectVoById(id);
        if (vo == null) {
            return null;
        }
        ensureCurrentUserCanAccessRole(vo.getCreatorUserId());
        List<Long> menuIds = roleMenuMapper.selectList(Wrappers.<SysCompanyRoleMenu>lambdaQuery()
                        .eq(SysCompanyRoleMenu::getCompanyRoleId, id))
                .stream()
                .map(SysCompanyRoleMenu::getMenuId)
                .filter(Objects::nonNull)
                .toList();
        if (!menuIds.isEmpty()) {
            vo.setMenuIds(menuIds);
        }
        return vo;
    }

    @Override
    public TableDataInfo<SysCompanyRoleVo> queryPageList(SysCompanyRoleBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysCompanyRole> lqw = buildQueryWrapper(bo);
        Page<SysCompanyRoleVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public List<SysCompanyRoleVo> queryList(SysCompanyRoleBo bo) {
        LambdaQueryWrapper<SysCompanyRole> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysCompanyRole> buildQueryWrapper(SysCompanyRoleBo bo) {
        LambdaQueryWrapper<SysCompanyRole> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(SysCompanyRole::getCompanyId).orderByAsc(SysCompanyRole::getRoleSort);
        lqw.eq(bo.getCompanyId() != null, SysCompanyRole::getCompanyId, bo.getCompanyId());
        lqw.like(StringUtils.isNotBlank(bo.getRoleName()), SysCompanyRole::getRoleName, bo.getRoleName());
        lqw.eq(StringUtils.isNotBlank(bo.getRoleKey()), SysCompanyRole::getRoleKey, bo.getRoleKey());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysCompanyRole::getStatus, bo.getStatus());
        lqw.eq(bo.getCreatorUserId() != null, SysCompanyRole::getCreatorUserId, bo.getCreatorUserId());
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser != null && ENTERPRISE_PORT.equals(loginUser.getLoginPort()) && !LoginHelper.isSuperAdmin()) {
            lqw.eq(SysCompanyRole::getCompanyId, loginUser.getCompanyId());
            if (isCurrentCompanyHead(loginUser)) {
                lqw.and(w -> w.eq(SysCompanyRole::getCreatorUserId, loginUser.getUserId())
                        .or()
                        .isNull(SysCompanyRole::getCreatorUserId));
            } else {
                lqw.eq(SysCompanyRole::getCreatorUserId, loginUser.getUserId());
            }
        }
        return lqw;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(SysCompanyRoleBo bo) {
        validateAssignableMenus(bo.getMenuIds(), bo.getCompanyId());
        SysCompanyRole add = MapstructUtils.convert(bo, SysCompanyRole.class);
        add.setCreatorUserId(LoginHelper.getUserId());
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
            insertRoleMenu(bo);
        }
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(SysCompanyRoleBo bo) {
        SysCompanyRole dbRole = baseMapper.selectById(bo.getId());
        if (dbRole == null) {
            return false;
        }
        ensureCurrentUserCanAccessRole(dbRole.getCreatorUserId());
        validateAssignableMenus(bo.getMenuIds(), dbRole.getCompanyId());
        SysCompanyRole update = MapstructUtils.convert(bo, SysCompanyRole.class);
        update.setCreatorUserId(dbRole.getCreatorUserId());
        boolean flag = baseMapper.updateById(update) > 0;
        if (flag) {
            roleMenuMapper.delete(Wrappers.<SysCompanyRoleMenu>lambdaQuery()
                    .eq(SysCompanyRoleMenu::getCompanyRoleId, bo.getId()));
            insertRoleMenu(bo);
        }
        return flag;
    }

    private void insertRoleMenu(SysCompanyRoleBo bo) {
        Long[] menuIds = bo.getMenuIds();
        if (menuIds == null || menuIds.length == 0) {
            return;
        }
        List<SysCompanyRoleMenu> list = new ArrayList<>();
        for (Long menuId : menuIds) {
            if (menuId == null) {
                continue;
            }
            SysCompanyRoleMenu rm = new SysCompanyRoleMenu();
            rm.setCompanyRoleId(bo.getId());
            rm.setMenuId(menuId);
            list.add(rm);
        }
        if (!list.isEmpty()) {
            roleMenuMapper.insertBatch(list);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (ids == null || ids.isEmpty()) {
            return false;
        }
        if (needLimitByCurrentCreator()) {
            Long currentUserId = LoginHelper.getUserId();
            long ownedCount = baseMapper.selectCount(Wrappers.<SysCompanyRole>lambdaQuery()
                    .in(SysCompanyRole::getId, ids)
                    .eq(SysCompanyRole::getCreatorUserId, currentUserId));
            if (ownedCount != ids.size()) {
                throw new ServiceException("仅允许删除当前账号创建的权限类型");
            }
        }
        roleMenuMapper.delete(Wrappers.<SysCompanyRoleMenu>lambdaQuery()
                .in(SysCompanyRoleMenu::getCompanyRoleId, ids));
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public Set<String> selectRoleKeys(Long userId, Long companyId) {
        // Query HotCompanySafetyManager to get role ID
        HotCompanySafetyManager manager = safetyManagerMapper.selectOne(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .select(HotCompanySafetyManager::getPermissionRoleId)
                .eq(HotCompanySafetyManager::getUserId, userId)
                .eq(HotCompanySafetyManager::getCompanyId, companyId)
                .eq(HotCompanySafetyManager::getIsDeleted, 0)
                .eq(HotCompanySafetyManager::getStatus, 1)
                .and(w -> w.eq(HotCompanySafetyManager::getIsResigned, 0).or().isNull(HotCompanySafetyManager::getIsResigned))
        );

        if (manager == null || manager.getPermissionRoleId() == null) {
            return Collections.emptySet();
        }

        SysCompanyRole role = baseMapper.selectOne(Wrappers.<SysCompanyRole>lambdaQuery()
                .select(SysCompanyRole::getRoleKey)
                .eq(SysCompanyRole::getId, manager.getPermissionRoleId())
                .eq(SysCompanyRole::getStatus, "0"));

        if (role != null && StringUtils.isNotBlank(role.getRoleKey())) {
            return Set.of(role.getRoleKey());
        }
        return Collections.emptySet();
    }

    private void validateAssignableMenus(Long[] menuIds, Long companyId) {
        if (!needLimitByCurrentCreator() || menuIds == null || menuIds.length == 0) {
            return;
        }
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("登录信息失效，请重新登录");
        }
        Long resolvedCompanyId = companyId != null ? companyId : loginUser.getCompanyId();
        List<SysMenuVo> currentMenus = menuService.selectMenuList(new SysMenuBo(), loginUser.getUserId(), resolvedCompanyId, loginUser.getLoginPort());
        Set<Long> currentMenuIds = currentMenus.stream().map(SysMenuVo::getMenuId).filter(Objects::nonNull).collect(java.util.stream.Collectors.toSet());
        boolean hasOutOfScopeMenu = Arrays.stream(menuIds).filter(Objects::nonNull).anyMatch(menuId -> !currentMenuIds.contains(menuId));
        if (hasOutOfScopeMenu) {
            throw new ServiceException("权限树仅允许选择当前账号已拥有的菜单权限");
        }
    }

    private void ensureCurrentUserCanAccessRole(Long creatorUserId) {
        if (!needLimitByCurrentCreator()) {
            return;
        }
        Long currentUserId = LoginHelper.getUserId();
        if (!Objects.equals(currentUserId, creatorUserId)) {
            throw new ServiceException("仅允许访问当前账号创建的权限类型");
        }
    }

    private boolean needLimitByCurrentCreator() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        return loginUser != null && ENTERPRISE_PORT.equals(loginUser.getLoginPort()) && !LoginHelper.isSuperAdmin();
    }

    private boolean isCurrentCompanyHead(LoginUser loginUser) {
        if (loginUser == null || loginUser.getCompanyId() == null || loginUser.getUserId() == null) {
            return false;
        }
        return safetyManagerMapper.exists(Wrappers.<HotCompanySafetyManager>lambdaQuery()
                .eq(HotCompanySafetyManager::getCompanyId, loginUser.getCompanyId())
                .eq(HotCompanySafetyManager::getUserId, loginUser.getUserId())
                .eq(HotCompanySafetyManager::getCompanyHead, 1L)
                .eq(HotCompanySafetyManager::getStatus, 1L)
                .eq(HotCompanySafetyManager::getIsDeleted, 0L)
                .and(w -> w.eq(HotCompanySafetyManager::getIsResigned, 0L).or().isNull(HotCompanySafetyManager::getIsResigned)));
    }
}
