package com.cyksj.service.mange.cms;


import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
import com.cyksj.mapper.manage.cms.CmsMenuMapper;
import com.cyksj.mapper.manage.cms.CmsRoleMapper;
import com.cyksj.mapper.manage.cms.CmsUserMapper;
import com.cyksj.mapper.manage.cms.CmsUserRoleMapper;
import com.cyksj.model.entity.CmsMenu;
import com.cyksj.model.entity.CmsRole;
import com.cyksj.model.entity.CmsUser;
import com.cyksj.model.entity.CmsUserRole;
import com.cyksj.service.mange.business.UserBusinessRateService;
import com.cyksj.service.mange.cms.manager.service.CacheService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/*
 *项目名: yicang-admin
 *文件名: CmsUserManager
 *创建者: JavaZou
 *创建时间:2022/9/30 13:59
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CmsUserManager {
	private final CacheService cacheService;

	private final CmsUserMapper cmsUserMapper;

	private final CmsRoleMapper cmsRoleMapper;

	private final CmsMenuMapper cmsMenuMapper;

	private final CmsUserRoleMapper cmsUserRoleMapper;

	private final UserBusinessRateService userBusinessRateService;

	private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();

	public CmsUser getUser(Long account) {
		return selectCacheByTemplate(() -> cacheService.getUserCache(account), () -> cmsUserMapper.selectById(account));
	}


	public void loadUserRedisCache(CmsUser user) throws Exception {
		cacheService.saveUser(user.getId());
		// 缓存用户角色
		cacheService.saveRoles(user.getId());
		// 缓存用户权限
		cacheService.savePermissions(user.getId());
	}

	public Set<String> getUserPermissions(Long account) {
		List<CmsMenu> cmsMenus = selectCacheByTemplate(() -> cacheService.getUserPermsCache(account), () -> cmsMenuMapper.getCmsMenusByAccount(account));
		if (cmsMenus == null) {
			return null;
		}
		return cmsMenus.stream().map(CmsMenu::getPerms).collect(Collectors.toSet());
	}

	public Set<String> getUserRoles(Long adminId) {
		List<CmsRole> cmsRoles = selectCacheByTemplate(
				() -> cacheService.getUserRoleCache(adminId),
				() -> cmsRoleMapper.getCmsRolesByAccount(adminId)
		);
		if (cmsRoles == null) {
			return null;
		}
		return cmsRoles.stream().map(CmsRole::getRoleName).collect(Collectors.toSet());
	}

	/**
	 * 缓存查询模板
	 *
	 * @param cacheSelector    查询缓存的方法
	 * @param databaseSelector 数据库查询方法
	 * @return T
	 */
	public static <T> T selectCacheByTemplate(Supplier<T> cacheSelector, Supplier<T> databaseSelector) {
		try {
			log.debug("查询redis ······");
			// 先查 Redis缓存
			T t = cacheSelector.get();
			if (t == null) {
				// 没有记录再查询数据库
				return databaseSelector.get();
			}
			return t;
		} catch (Exception e) {
			// 缓存查询出错，则去数据库查询
			log.error("redis查询 error：", e);
			log.debug("查询数据库 ······");
			return databaseSelector.get();
		}
	}

	public void saveUserRoleRelation(Long userId, String roleIds) {
		if (!userBusinessRateService.isBusiness(userId)) {
			userBusinessRateService.deleteBusinessRateByUid(userId);
		}
		Arrays.stream(roleIds.split(",")).collect(Collectors.toSet()).forEach(roleId -> {
			CmsRole cmsRole = cmsRoleMapper.selectById(roleId);
			if (cmsRole != null && cmsRole.getRoleName().contains("商务")) {
				TASK_EXECUTOR.execute(() -> userBusinessRateService.saveBusinessRate(userId));
			}
			cmsUserRoleMapper.insert(new CmsUserRole(userId, Long.valueOf(roleId)));
		});
	}

	public void delUserRoleRelation(Long userId) throws Exception {
		cmsUserRoleMapper.delete(Wrappers.lambdaQuery(CmsUserRole.class).eq(CmsUserRole::getUserId, userId));
		//删除用户缓存
		cacheService.deleteUserCache(userId);
		//删除角色缓存
		cacheService.delUserRoleCache(userId);
		//删除权限缓存
		cacheService.delUserPermissionsCache(userId);
	}

	public void saveUserRoleRelationAndCache(CmsUser cmsUser, String roles) throws Exception {
		//用户角色关联入库
		this.saveUserRoleRelation(cmsUser.getId(), roles);
		//缓存用户最数据
		loadUserRedisCache(cmsUser);
	}
}
