package openjoe.smart.sso.server.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import openjoe.smart.sso.base.entity.TokenMenu;
import openjoe.smart.sso.base.entity.TokenPermission;
import openjoe.smart.sso.server.dto.PermissionDTO;
import openjoe.smart.sso.server.dto.TreeDTO;
import openjoe.smart.sso.server.entity.Permission;
import openjoe.smart.sso.server.manager.PermissionManager;
import openjoe.smart.sso.server.mapper.PermissionMapper;
import openjoe.smart.sso.server.service.PermissionService;
import openjoe.smart.sso.server.service.RolePermissionService;
import openjoe.smart.sso.server.service.UserRoleService;
import openjoe.smart.sso.server.stage.core.Tree;
import openjoe.smart.sso.server.stage.mybatisplus.service.impl.BaseServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service("permissionService")
public class PermissionServiceImpl extends BaseServiceImpl<PermissionMapper, Permission> implements PermissionService, PermissionManager {

	@Autowired
	private RolePermissionService rolePermissionService;
	@Autowired
	private UserRoleService userRoleService;

	@Override
    public List<PermissionDTO> selectTree(Long appId, Long roleId, Boolean isEnable) {
        List<Permission> permissionList = findByAppId(appId, isEnable);
        if (roleId == null) {
            return addRoot(Tree.build(permissionList, r -> convertToDto(r, false)));
        }

        Set<Long> permissionIdSet = rolePermissionService.findPermissionIdSetByRoleIds(Collections.singletonList(roleId));
        return addRoot(Tree.build(permissionList, r -> convertToDto(r, permissionIdSet.contains(r.getId()))));
    }
	
	public List<PermissionDTO> addRoot(List<TreeDTO> list) {
        PermissionDTO dto = new PermissionDTO();
        dto.setName("根节点");
        dto.setChildren(list);
		List<PermissionDTO> dtoList = new ArrayList<>();
		dtoList.add(dto);
        return dtoList;
    }
	
	private PermissionDTO convertToDto(Permission r, Boolean checked) {
        PermissionDTO dto = new PermissionDTO();
        BeanUtils.copyProperties(r, dto);
        dto.setChecked(checked);
        return dto;
    }
	
    private List<Permission> findByAppId(Long appId, Boolean isEnable) {
		LambdaQueryWrapper<Permission> wrapper =  Wrappers.lambdaQuery();
		wrapper.eq(appId != null, Permission::getAppId, appId);
		wrapper.eq(isEnable != null, Permission::getIsEnable, isEnable);
		wrapper.orderByDesc(Permission::getSort).orderByAsc(Permission::getId);
		return list(wrapper);
    }

	@Override
	@Transactional
	public void delete(Long id, Long appId) {
		List<Long> idList = new ArrayList<>();

		List<Permission> list = findByAppId(appId, null);
		loopSubList(id, idList, list);
		idList.add(id);

		rolePermissionService.deleteByPermissionIds(idList);

		removeByIds(idList);
	}

	// 递归方法，删除子权限
	protected void loopSubList(Long id, List<Long> idList, List<Permission> list) {
		for (Permission p : list) {
			if (id.equals(p.getParentId())) {
				idList.add(p.getId());
				loopSubList(p.getId(), idList, list);
			}
		}
	}

	@Override
	public void deleteByAppIds(Collection<Long> idList) {
		LambdaQueryWrapper<Permission> wrapper =  Wrappers.lambdaQuery();
		wrapper.in(Permission::getAppId, idList);
		remove(wrapper);
	}

	@Override
	public TokenPermission getUserPermission(Long userId, Long appId) {
		List<Permission> list = findByAppId(appId, true);
		if(CollectionUtils.isEmpty(list)){
			return new TokenPermission(Collections.emptySet(), Collections.emptySet(), Collections.emptyList());
		}
		Set<Long> permissionIdSet = getUserPermissionIdSet(userId);
		Set<String> permissionSet;
		Set<String> noPermissionSet;
		if (CollectionUtils.isEmpty(permissionIdSet)) {
			permissionSet = Collections.emptySet();
			noPermissionSet = list.stream().map(t -> t.getUrl()).collect(Collectors.toSet());
		}
		else{
			permissionSet = list.stream().filter(t -> permissionIdSet.contains(t.getId())).map(t -> t.getUrl()).collect(Collectors.toSet());
			noPermissionSet= list.stream().filter(t -> !permissionIdSet.contains(t.getId())).map(t -> t.getUrl()).collect(Collectors.toSet());
		}
		List<TokenMenu> menuList = list.stream().filter(t -> t.getIsMenu() && !noPermissionSet.contains(t.getUrl())).map(t->{
			TokenMenu dto = new TokenMenu();
			BeanUtils.copyProperties(t, dto);
			return dto;
		}).collect(Collectors.toList());
		return new TokenPermission(permissionSet, noPermissionSet, menuList);
	}

	private Set<Long> getUserPermissionIdSet(Long userId){
		List<Long> roleIdList = userRoleService.findRoleIdListByUserId(userId);
		if (CollectionUtils.isEmpty(roleIdList)) {
			return Collections.emptySet();
		}
		return rolePermissionService.findPermissionIdSetByRoleIds(roleIdList);
	}
}
