package com.xunhong.erp.turbo.rbac.infrastructure.gateway;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xunhong.erp.turbo.api.rbac.dto.cmd.PermissionCreateCmd;
import com.xunhong.erp.turbo.api.rbac.dto.cmd.PermissionDestroyCmd;
import com.xunhong.erp.turbo.api.rbac.dto.cmd.PermissionUpdateCmd;
import com.xunhong.erp.turbo.api.rbac.dto.qry.PermissionListQry;
import com.xunhong.erp.turbo.api.rbac.dto.qry.PermissionPageQry;
import com.xunhong.erp.turbo.api.rbac.dto.qry.PermissionShowQry;
import com.xunhong.erp.turbo.api.rbac.dto.qry.UserPermissionQry;
import com.xunhong.erp.turbo.api.rbac.exception.RbacErrorCode;
import com.xunhong.erp.turbo.api.rbac.exception.RbacException;
import com.xunhong.erp.turbo.datasource.domain.entity.BaseDO;
import com.xunhong.erp.turbo.rbac.domain.entity.Permission;
import com.xunhong.erp.turbo.rbac.domain.gateway.PermissionGateway;
import com.xunhong.erp.turbo.rbac.infrastructure.convert.PermissionConvert;
import com.xunhong.erp.turbo.rbac.infrastructure.entity.MenuDO;
import com.xunhong.erp.turbo.rbac.infrastructure.entity.PermissionDO;
import com.xunhong.erp.turbo.rbac.infrastructure.mapper.MenuMapper;
import com.xunhong.erp.turbo.rbac.infrastructure.mapper.PermissionMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class PermissionGatewayImpl implements PermissionGateway {
	private final PermissionMapper permissionMapper;
	private final PermissionConvert permissionConvert;

	private final MenuMapper menuMapper;

	@Override
	public List<Permission> list(PermissionListQry permissionListQry) {
		LambdaQueryWrapper<PermissionDO> queryWrapper = Wrappers.lambdaQuery(PermissionDO.class);
		queryWrapper.orderByDesc(PermissionDO::getSlug, BaseDO::getCreatedAt);

		List<PermissionDO> permissionDOList = permissionMapper.selectList(queryWrapper);
		return permissionDOList.stream().map(permissionConvert::toPermission).toList();
	}

	@Override
	public List<Permission> userPermission(UserPermissionQry userPermissionQry) {
		List<PermissionDO> permissionDOList = permissionMapper.listByRoleList(userPermissionQry);
		return permissionDOList.stream().map(permissionConvert::toPermission).toList();
	}

	@Override
	public IPage<Permission> page(PermissionPageQry permissionPageQry) {
		LambdaQueryWrapper<PermissionDO> queryWrapper = Wrappers.lambdaQuery(PermissionDO.class);
		queryWrapper.like(StrUtil.isNotEmpty(permissionPageQry.getSlug()), PermissionDO::getSlug, permissionPageQry.getSlug());
		queryWrapper.like(StrUtil.isNotEmpty(permissionPageQry.getName()), PermissionDO::getName, permissionPageQry.getName());
		queryWrapper.orderByDesc(PermissionDO::getSlug, BaseDO::getCreatedAt);
		Page<PermissionDO> page = new Page<>(permissionPageQry.getPageIndex(), permissionPageQry.getPageSize());
		page = permissionMapper.selectPage(page, queryWrapper);
		return page.convert(permissionConvert::toPermission);
	}

	@Override
	public Permission show(PermissionShowQry permissionShowQry) {
		PermissionDO permissionDO = permissionMapper.selectById(permissionShowQry.getPermissionId());
		return permissionConvert.toPermission(permissionDO);
	}

	@Override
	public Permission create(PermissionCreateCmd permissionCreateCmd) {
		PermissionDO permissionDO = permissionConvert.toPermissionDO(permissionCreateCmd);
		permissionMapper.insert(permissionDO);
		return permissionConvert.toPermission(permissionDO);
	}

	@Override
	public Permission update(PermissionUpdateCmd permissionUpdateCmd) {
		PermissionDO permissionDO = permissionConvert.toPermissionDO(permissionUpdateCmd);
		permissionMapper.updateById(permissionDO);
		return permissionConvert.toPermission(permissionDO);
	}

	@Override
	public void destroy(PermissionDestroyCmd permissionDestroyCmd) {
		// 判断权限是否被菜单绑定
		LambdaQueryWrapper<MenuDO> queryWrapper = Wrappers.lambdaQuery(MenuDO.class);
		queryWrapper.eq(MenuDO::getPermissionId, permissionDestroyCmd.getPermissionId());

		if (menuMapper.selectCount(queryWrapper) > 0) {
			throw new RbacException(RbacErrorCode.PERMISSION_USED);
		}

		permissionMapper.deleteById(permissionDestroyCmd.getPermissionId());
	}
}
