/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.crunii.com</a>
 */
package com.crunii.micro.service.sysmgr.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.crunii.micro.common.constants.CommonConstants;
import com.crunii.micro.common.dto.CBTree;
import com.crunii.micro.common.dto.OrderProp;
import com.crunii.micro.common.dto.PageRsp;
import com.crunii.micro.common.dto.TreeNode;
import com.crunii.micro.core.cache.TsmURLCache;
import com.crunii.micro.domain.common.jdbc.BaseJdbcTemplate;
import com.crunii.micro.domain.dto.TsmRoleDto;
import com.crunii.micro.domain.dto.Worker;
import com.crunii.micro.domain.dto.sys.MenuExtend;
import com.crunii.micro.domain.entity.main.*;
import com.crunii.micro.domain.repo.main.*;
import com.crunii.micro.domain.util.CurrWorkerUtil;
import com.crunii.micro.service.sysmgr.dto.sysmgr.*;
import com.crunii.micro.service.sysmgr.jdbc.AuthJdbcDao;
import com.crunii.micro.service.sysmgr.jdbc.MenuJdbcDao;
import com.crunii.micro.service.sysmgr.jdbc.RoleJdbcDao;
import com.crunii.micro.service.sysmgr.service.AuthService;
import com.crunii.micro.service.sysmgr.service.TsmAppService;
import com.google.common.base.Stopwatch;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 田平 create 2018年10月31日下午4:40:16
 */
@Service
public class AuthServiceImpl implements AuthService {

	@Resource(name = "mainJT")
	protected BaseJdbcTemplate jdbcTemplate;


	@Autowired
	private AuthJdbcDao authJdbcDao;
	@Autowired
	private MenuJdbcDao menuJdbcDao;
	@Autowired
	private RoleJdbcDao roleJdbcDao;
	@Autowired
	private TsmRoleRepo tsmRoleRepo;
	@Autowired
	private TsmMenuRepo tsmMenuRepo;
	@Autowired
	private TsmRoleMenuRepo tsmRoleMenuRepo;
	@Autowired
	private TsmWorkerRoleRepo tsmWorkerRoleRepo;
	@Autowired
	private TsmRoleUrlGroupRepo tsmRoleUrlGroupRepo;
	@Autowired
	private TsmUrlGroupRepo tsmUrlGroupRepo;
	@Autowired
	private TsmUrlRepo tsmUrlRepo;

	@Autowired
	private TsmRoleButtonRepo roleButtonRepo;

	@Autowired
	private TsmURLCache tsmURLCache;

	@Autowired
	private TsmAppButtonRepo buttonRepo;

	@Autowired
	private TsmRoleAppRepo tsmRoleAppRepo;

	@Override
	public CBTree getCheckedRoleTreeNode(int roleId) {
		List<MenuInfo> menuInfos = authJdbcDao.getRoleMenus(roleId);
		List<TsmMenu> allMenus=new ArrayList<>();
		List<Object> params = new ArrayList<>();
		Boolean isSuper=false;
		Worker worker = getWorker();


//		Worker worker = new Worker();
//		worker.setLoginId(9999);
//		List<TsmRoleDto> roleDtos=new ArrayList<>();
//		TsmRoleDto tsmRoleDto = new TsmRoleDto();
//		tsmRoleDto.setRoleName("超级管理员");
//		roleDtos.add(tsmRoleDto);
//		worker.setRoles(roleDtos);

		params.add(worker.getLoginId()+"");
		Integer num = jdbcTemplate.queryForInt("select count(1) from tsm_property_value a,tsm_property b WHERE a.del_flag=0 and a.state=1 and a.prop_id=b.prop_id AND b.prop_code='super-account' and value_code= ? ",params.toArray());

		List<TsmRoleDto> roles = worker.getRoles();
		if (num!=null&&num>0){
			isSuper=true;
		}
		//是否超级管理员
		if (isSuper){
			allMenus = tsmMenuRepo.findByProp("state", CommonConstants.STATE_VALID);
		}else {
			allMenus = jdbcTemplate.queryForBeans(TsmMenu.class,"select distinct d.* from TSM_WORKER_ROLE a ,TSM_ROLE b, TSM_ROLE_MENU c ,tsm_menu d where a.role_id=b.role_id and a.role_id=c.role_id  and c.menu_code=d.menu_code and d.state=1 and login_id = ? ",worker.getLoginId());
		}


		List<TsmMenu> finalAllMenus = allMenus;
		List<String> roleMenuCodes = menuInfos.stream()
				.filter(menu -> menu.getMenuType() != CommonConstants.MENU_TYPE_DIR)
				.filter(m -> {
					//只返回选中的叶子节点
					boolean leaf = finalAllMenus.stream()
							.filter(am -> am.getParentMenuCode().equals(m.getMenuCode()))
							.findFirst()
							.isPresent();
					return !leaf;
				})
				.map(menu -> menu.getMenuCode())
				.collect(Collectors.toList());

 		List<TreeNode<MenuExtend>> allNodes = allMenus.stream().map(menu -> {
			TreeNode<MenuExtend> node = new TreeNode<>();
			node.setNodeId(menu.getMenuCode());
			node.setNodeName(menu.getMenuName());
			node.setLeaf(menu.getMenuType() == CommonConstants.MENU_TYPE_BUTTON);
			node.setIcon(menu.getIcon());
			//设置NodeData
			MenuExtend me = new MenuExtend();
			BeanUtils.copyProperties(menu, me);

			if (me.getButtonUrlId() > 0) {
				TsmUrl url = tsmURLCache.get(me.getButtonUrlId());
//				TsmUrl url = tsmUrlRepo.getOne(me.getButtonUrlId());
				if (url != null) {
					me.setUrlName(url.getUrlName());
					me.setUrlPath(url.getUrlPath());
				}
			}
			node.setNodeData(me);
			return node;
		}).collect(Collectors.toList());
		allNodes.forEach(node -> {
			setChildren(node, allNodes);
		});

		List<TreeNode<MenuExtend>> topNodes = allNodes.stream().filter(node -> {
			return node.getNodeData().getParentMenuCode().equals(CommonConstants.ROOT_NODE_ID);
		}).sorted(new Comparator<TreeNode<MenuExtend>>() {
			@Override
			public int compare(TreeNode<MenuExtend> o1, TreeNode<MenuExtend> o2) {
				return Integer.compare(o1.getNodeData().getSortId(), o2.getNodeData().getSortId());
			}
		}).collect(Collectors.toList());

		// 过滤菜单
//		if(getWorker().getLoginId() != 9999){
//			List<Integer> roleIds = jdbcTemplate.queryForList("select role_id from TSM_WORKER_ROLE where login_id = ?", Integer.class, getWorker().getLoginId());
//			for(int r = roleIds.size() - 1; r >= 0; r--){
//				if(0 == jdbcTemplate.queryForObject("select a.state from TSM_ROLE a where a.role_id = ?",Integer.class, roleIds.get(r))){
//					roleIds.remove(roleIds.get(r));
//				}
//			}
//			Set<String> menuCodes = new HashSet<>();
//			for(Integer rId : roleIds){
//				menuCodes.addAll(jdbcTemplate.queryForList("select menu_code from TSM_ROLE_MENU where role_id = ?", String.class, rId));
//			}
//			if(CollectionUtils.isEmpty(menuCodes)){
//				topNodes.clear();
//			}
//			else{
//				for(int i = topNodes.size()-1; i>=0; i--){
//					if(menuCodes.contains(topNodes.get(i).getNodeData().getMenuCode())){
//						if(CollectionUtils.isEmpty(topNodes.get(i).getChildren())){
//							continue;
//						}
//						else{
//							for(int j = topNodes.get(i).getChildren().size()-1; j>=0; j--){
//								if(menuCodes.contains(topNodes.get(i).getChildren().get(j).getNodeData().getMenuCode())){
//									if(CollectionUtils.isEmpty(topNodes.get(i).getChildren().get(j).getChildren())){
//										continue;
//									}
//									else{
//										for(int l = topNodes.get(i).getChildren().get(j).getChildren().size()-1; l>=0; l--){
//											if(!menuCodes.contains(topNodes.get(i).getChildren().get(j).getChildren().get(l).getNodeData().getMenuCode())){
//												topNodes.get(i).getChildren().get(j).getChildren().remove(menuCodes.contains(topNodes.get(i).getChildren().get(j).getChildren().get(l)));
//											}
//										}
//									}
//								}
//								else{
//									topNodes.get(i).getChildren().remove(topNodes.get(i).getChildren().get(j));
//								}
//							}
//						}
//					}
//					else{
//						topNodes.remove(topNodes.get(i));
//					}
//				}
//			}
//		}

		CBTree<MenuExtend> cbTree = new CBTree<>();
		cbTree.setCheckedIds(roleMenuCodes);
		cbTree.setNodes(topNodes);
		return cbTree;
	}

	@Override public CBTree getRoleBtnTreeNode(int roleId) {
		List<String> checkRoleBtn = authJdbcDao.getCheckRoleBtn(roleId);
		List<TsmAppButton> allByState = buttonRepo.findAllByState(CommonConstants.STATE_VALID);

		List<TreeNode<TsmAppButton>> rootCollect = allByState.stream().filter(item->item.getParentId()== TsmAppService.DEF_APP_BUTTON_ID).map(item -> {
			TreeNode<TsmAppButton> treeNode = new TreeNode<>();
			treeNode.setNodeId(item.getBtnId().toString());
			treeNode.setNodeName(item.getName());
			treeNode.setParentNodeId(item.getParentId().toString());
			treeNode.setNodeData(item);
			return treeNode;
		}).collect(Collectors.toList());

		List<TreeNode<TsmAppButton>> subCollect = allByState.stream().filter(item->item.getParentId() != TsmAppService.DEF_APP_BUTTON_ID).map(item -> {
			TreeNode<TsmAppButton> treeNode = new TreeNode<>();
			treeNode.setNodeId(item.getBtnId().toString());
			treeNode.setNodeName(item.getName());
			treeNode.setParentNodeId(item.getParentId().toString());
			treeNode.setNodeData(item);
			return treeNode;
		}).collect(Collectors.toList());

		setBtnChildren(rootCollect,subCollect);

		CBTree cbTree = new CBTree();
		cbTree.setCheckedIds(checkRoleBtn);
		cbTree.setNodes(rootCollect);
		return cbTree;
	}

	@Override
	public CBTree getCheckedAuthTreeNode(int loginId) {
		List<TsmMenu> allMenus = tsmMenuRepo.findByProp("state", CommonConstants.STATE_VALID);
		//只返回选中的叶子节点
		List<String> authMenuCodes = getAuthMenus(loginId).stream()
				.filter(m -> {
					boolean leaf = allMenus.stream()
							.filter(am -> am.getParentMenuCode().equals(m.getMenuCode()))
							.findFirst()
							.isPresent();
					return !leaf;
				})
				.map(menu -> menu.getMenuCode())
				.collect(Collectors.toList());

		List<TreeNode<MenuExtend>> authNodes = allMenus.stream().map(menu -> {
			TreeNode<MenuExtend> node = new TreeNode<>();
			node.setNodeId(menu.getMenuCode());
			node.setNodeName(menu.getMenuName());
			node.setLeaf(menu.getMenuType() == CommonConstants.MENU_TYPE_BUTTON);
			node.setIcon(menu.getIcon());

			//设置NodeData
			MenuExtend me = new MenuExtend();
			BeanUtils.copyProperties(menu, me);
			if (me.getButtonUrlId() > 0) {
				TsmUrl url = tsmURLCache.get(me.getButtonUrlId());
//				TsmUrl url = tsmUrlRepo.getOne(me.getButtonUrlId());
				if (url != null) {
					me.setUrlName(url.getUrlName());
					me.setUrlPath(url.getUrlPath());
				}
			}

			node.setNodeData(me);
			return node;
		}).collect(Collectors.toList());
		authNodes.forEach(node -> {
			setChildren(node, authNodes);
		});

		List<TreeNode<MenuExtend>> topNodes = authNodes.stream().filter(node -> {
			return node.getNodeData().getParentMenuCode().equals(CommonConstants.ROOT_NODE_ID);
		}).sorted(Comparator.comparingInt(o -> o.getNodeData().getSortId())).collect(Collectors.toList());

		CBTree<MenuExtend> cbTree = new CBTree<>();
		cbTree.setCheckedIds(authMenuCodes);
		cbTree.setNodes(topNodes);
		return cbTree;
	}

	@Override
	public List<AuthRoleCB> getCheckedAuthRole(int loginId) {
		List<Integer> roleIds = getAuthRoles(loginId).stream().map(role -> role.getRoleId()).collect(Collectors.toList());
		List<TsmRole> allRoles = tsmRoleRepo.findByProp("state", CommonConstants.STATE_VALID);

		List<AuthRoleCB> authRoles = allRoles.stream().map(role -> {
			AuthRoleCB authRole = new AuthRoleCB();
			BeanUtils.copyProperties(role, authRole);
			if (roleIds.contains(authRole.getRoleId())) {
				authRole.setChecked(true);
			}
			return authRole;
		}).collect(Collectors.toList());

		return authRoles;
	}

	@Override
	public void doWorkerRelaRole(WorkerRelaRole rela) {
		Map<String, Object> props = new HashMap<>();
		props.put("loginId", rela.getLoginId());
		List<TsmWorkerRole> oldRelas = tsmWorkerRoleRepo.findByProps(props);
		tsmWorkerRoleRepo.deleteAll(oldRelas);
		tsmWorkerRoleRepo.flush();
		List<TsmWorkerRole> newRelas = new ArrayList<>(rela.getRoleIds().size());
		rela.getRoleIds().forEach(roleId -> {
			TsmWorkerRole tsmWorkerRole = new TsmWorkerRole();
			tsmWorkerRole.setLoginId(rela.getLoginId());
			tsmWorkerRole.setRoleId(roleId);
			newRelas.add(tsmWorkerRole);
		});
		tsmWorkerRoleRepo.saveAll(newRelas);
	}

	@Override
	public void doRoleRelaUrlGroup(RoleRelaUrlGroup rela) {
		Map<String, Object> props = new HashMap<>();
		props.put("roleId", rela.getRoleId());
		List<TsmRoleUrlGroup> oldRelas = tsmRoleUrlGroupRepo.findByProps(props);
		tsmRoleUrlGroupRepo.deleteAll(oldRelas);
		tsmRoleUrlGroupRepo.flush();
		List<TsmRoleUrlGroup> newRelas = new ArrayList<TsmRoleUrlGroup>(rela.getGroupIds().size());
		rela.getGroupIds().stream().forEach((groupId) -> {
			TsmRoleUrlGroup tsmRoleUrlGroup = new TsmRoleUrlGroup();
			tsmRoleUrlGroup.setRoleId(rela.getRoleId());
			tsmRoleUrlGroup.setGroupId(groupId);
			newRelas.add(tsmRoleUrlGroup);
		});
		tsmRoleUrlGroupRepo.saveAll(newRelas);
	}

	@Override public void doRoleRelaButton(RoleButton rela) {
		Map<String, Object> props = new HashMap<>();
		props.put("roleId", rela.getRoleId());
		List<TsmRoleButton> oldRelas = roleButtonRepo.findByProps(props);
		roleButtonRepo.deleteAll(oldRelas);
		roleButtonRepo.flush();
		List<TsmRoleButton> collect = rela.getBtnIds().stream().map(id -> {
			TsmRoleButton tsmRoleButton = new TsmRoleButton();
			tsmRoleButton.setRoleId(rela.getRoleId());
			tsmRoleButton.setBtnId(id);
			return tsmRoleButton;
		}).collect(Collectors.toList());
		roleButtonRepo.saveAll(collect);
	}

	@Override public List<String> getBtnIds(Worker worker) {
		return authJdbcDao.getUserRoleBtnCode(worker.getLoginId());
//		List<TsmRoleButton> all = roleButtonRepo.findAll();
//		all.stream().filter(btn)
//		buttonRepo.
	}

	@Override
	public void doRoleAssociationApp(RoleApp roleApp) {
		Map<String, Object> props = new HashMap<>();
		props.put("roleId", roleApp.getRoleId());
		List<TsmRoleApp> oldRoleApp = tsmRoleAppRepo.findByProps(props);
		tsmRoleAppRepo.deleteAll(oldRoleApp);
		tsmRoleAppRepo.flush();
		List<TsmRoleApp> collect = roleApp.getAppId().stream().map(id -> {
			TsmRoleApp tsmRoleApp = new TsmRoleApp();
			tsmRoleApp.setRoleId(roleApp.getRoleId());
			tsmRoleApp.setAppId(id);
			return tsmRoleApp;
		}).collect(Collectors.toList());
		tsmRoleAppRepo.saveAll(collect);
	}

	@Override
	public List<RoleUrlGroupCB> getCheckedRoleUrlGroup(int roleId) {
		List<Integer> relaGroups = roleJdbcDao.getUrlGroupOfRole(roleId).stream().map(urlGroup -> urlGroup.getGroupId()).collect(Collectors.toList());
		List<TsmUrlGroup> validUrlGroups = tsmUrlGroupRepo.findByProp("state", 1);
		List<RoleUrlGroupCB> rug = new ArrayList<RoleUrlGroupCB>(validUrlGroups.size());
		validUrlGroups.stream().forEach(group -> {
			RoleUrlGroupCB roleUrlGroup = new RoleUrlGroupCB();
			BeanUtils.copyProperties(group, roleUrlGroup);
			if (relaGroups.contains(group.getGroupId())) {
				roleUrlGroup.setChecked(true);
			}
			rug.add(roleUrlGroup);
		});
		return rug;
	}

	@Override
	public void doRoleRelaMenu(RoleRelaMenu rela) {
		Map<String, Object> props = new HashMap<>();
		props.put("roleId", rela.getRoleId());
		List<TsmRoleMenu> oldRelas = tsmRoleMenuRepo.findByProps(props);
		tsmRoleMenuRepo.deleteAll(oldRelas);
		tsmRoleMenuRepo.flush();
		List<TsmRoleMenu> newRelas = new ArrayList<>();
		rela.getMenuCodes().forEach(menuCode -> {
			TsmRoleMenu tsmRoleMenu = new TsmRoleMenu();
			tsmRoleMenu.setRoleId(rela.getRoleId());
			tsmRoleMenu.setMenuCode(menuCode);
			//tsmRoleMenu.setHalfChecked(0);// 全选中
			newRelas.add(tsmRoleMenu);
		});

		tsmRoleMenuRepo.saveAll(newRelas);
	}

	@Override
	public List<TsmRole> getAuthRoles(int loginId) {
		List<TsmRole> roles = null;
		if (CommonConstants.SUPER_LOGIN_IDS.contains(loginId)) {
			// roles = tsmRoleRepo.findByProp("state", 1);
			// 超级管理员所有权限都特殊判断
			roles = new ArrayList<>();
		} else {
			roles = authJdbcDao.getAuthRoles(loginId);
			if(CollectionUtils.isEmpty(roles)){
				TsmRole one = tsmRoleRepo.getOne(CommonConstants.COMMON_ROLE_ID);
				roles = new ArrayList<>();
				roles.add(one);
			}
		}
		return roles;
	}

	@Override
	public List<TsmUrl> getAuthUrls(int loginId) {
		List<TsmUrl> urls;
		if (CommonConstants.SUPER_LOGIN_IDS.contains(loginId)) {
			// roles = tsmRoleRepo.findByProp("state", 1);
			// 超级管理员所有权限都特殊判断
			urls = new ArrayList<>();
		} else {
			urls = authJdbcDao.getAuthUrls(loginId);
			if(CollectionUtils.isEmpty(urls)){
				urls = authJdbcDao.findPublicAuth(CommonConstants.COMMON_GROUP_IDS);
			}
		}
		return urls;
	}

	@Override
	public List<TsmMenu> getAuthMenus(int loginId) {
		List<TsmMenu> menus;
		if (CommonConstants.SUPER_LOGIN_IDS.contains(loginId)) {
			menus = tsmMenuRepo.findByProp("state", 1, new OrderProp("parentMenuCode"), new OrderProp("sortId"));
		} else {
			menus = authJdbcDao.getAuthMenus(loginId);
		}
		return menus;
	}

	@Override
	public List<TreeNode<MenuExtend>> getAuthTreeNode(int loginId) {
		List<TsmMenu> menus = getAuthMenus(loginId);
		Stopwatch started = Stopwatch.createStarted();
		List<TreeNode<MenuExtend>> authNodes = menus.stream().map(menu -> {
			TreeNode<MenuExtend> node = new TreeNode<>();
			node.setNodeId(menu.getMenuCode());
			node.setNodeName(menu.getMenuName());
			node.setLeaf(menu.getMenuType() == CommonConstants.MENU_TYPE_BUTTON);
			node.setIcon(menu.getIcon());
			//设置节点数据
			MenuExtend me = new MenuExtend();
			BeanUtils.copyProperties(menu, me);
			if (me.getButtonUrlId() > 0) {
				TsmUrl url = tsmURLCache.get(me.getButtonUrlId());
//				TsmUrl url = tsmUrlRepo.getOne(me.getButtonUrlId());
				if (url != null) {
					me.setUrlName(url.getUrlName());
					me.setUrlPath(url.getUrlPath());
				}
			}
			node.setNodeData(me);
			return node;
		}).collect(Collectors.toList());
		long elapsed = started.stop().elapsed(TimeUnit.MILLISECONDS);
		System.out.println(elapsed+"ms");
		authNodes.forEach(node -> {
			setChildren(node, authNodes);
		});
		List<TreeNode<MenuExtend>> topNodes = authNodes.stream().filter(node -> {
			return node.getNodeData().getParentMenuCode().equals(CommonConstants.ROOT_NODE_ID);
		}).sorted(Comparator.comparingInt(o -> o.getNodeData().getSortId()))
				.collect(Collectors.toList());
		return topNodes;
	}

	private void setChildren(TreeNode<MenuExtend> node, List<TreeNode<MenuExtend>> authNodes) {
		if (node.getNodeData().getMenuType() != CommonConstants.MENU_TYPE_BUTTON) {
			List<TreeNode<MenuExtend>> subNodes = authNodes.stream().filter(curr -> {
				return curr.getNodeData().getParentMenuCode().equals(node.getNodeId());
			}).sorted(Comparator.comparingInt(o -> o.getNodeData().getSortId())).collect(Collectors.toList());
			node.setChildren(subNodes);
		}
	}

	private void setBtnChildren(List<TreeNode<TsmAppButton>> allNode, List<TreeNode<TsmAppButton>> subNode) {
		allNode.forEach(item->{
			List<TreeNode<TsmAppButton>> collect = subNode.stream().filter(subItem -> item.getNodeId().equals(subItem.getParentNodeId()))
					.collect(Collectors.toList());
			if(collect.isEmpty()){
				item.setLeaf(true);
			}
			item.setChildren(collect);
			setBtnChildren(collect,subNode);
		});
	}

	/**
	 * 获取登录用户
	 */
	private Worker getWorker() {
		Worker worker = CurrWorkerUtil.getCurrWorker();
		if (ObjectUtil.isEmpty(worker)) {
			throw new RuntimeException("获取当前登录用户失败");
		}
		return worker;
	}

}
