/*
 * Copyright (c) 2020 yifu4cloud Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.yifu.cloud.plus.v1.yifu.admin.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yifu.cloud.plus.v1.yifu.admin.api.entity.*;
import com.yifu.cloud.plus.v1.yifu.admin.api.vo.SysDataAuthVO;
import com.yifu.cloud.plus.v1.yifu.admin.mapper.SysDataAuthMapper;
import com.yifu.cloud.plus.v1.yifu.admin.service.*;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CacheConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: 数据权限配置服务实现
 * @Author: hgw
 * @Date: 2022/6/8 17:20
 **/
@Service
@RequiredArgsConstructor
public class SysDataAuthServiceImpl extends ServiceImpl<SysDataAuthMapper, SysDataAuth> implements SysDataAuthService {

	// 权限-部门
	private final SysDataAuthDeptRelService authDeptRelService;
	// 权限-菜单（type：类型：1：创建人；2：结算主体；3部门）
	private final SysDataAuthMenuRelService authMenuRelService;
	// 权限-自定义sql
	private final SysDataAuthDiySqlService diySqlService;
	// 自定义sql-菜单
	private final SysDiySqlMenuRelService diySqlMenuRelService;

	// 缓存信息
	private final CacheManager cacheManager;

	/**
	 * @Description: 刷新缓存
	 * @Author: hgw
	 * @Date: 2022/6/20 17:59
	 * @return: void
	 **/
	@Override
	public void refreshAuth(SysDataAuth sysDataAuth) {
		List<SysDataAuth> authList = baseMapper.getSysDataAuthPage(sysDataAuth);
		if (authList != null && !authList.isEmpty()) {
			sysDataAuth = authList.get(0);
			R<SysDataAuthVO> sysDataAuthVOR = this.getByMainId(sysDataAuth.getId());
			if (sysDataAuthVOR != null && sysDataAuthVOR.getData() != null) {
				Cache cache = cacheManager.getCache(CacheConstants.DATA_AUTH_DETAILS + sysDataAuth.getLinkType());
				if (cache != null) {
					this.refreshAuthCache(sysDataAuthVOR.getData(), sysDataAuth, cache);
				}
			}
		}
	}

	/**
	 * @Description: 刷新缓存-核心
	 * @Author: hgw
	 * @Date: 2022/6/20 17:56
	 * @return: void
	 **/
	private void refreshAuthCache(SysDataAuthVO sysDataAuthVO, SysDataAuth sysDataAuth, Cache cache) {
		List<SysDataAuthDeptRel> authDeptList = sysDataAuthVO.getAuthDeptList();
		List<SysDataAuthDiySql> authSqlList = sysDataAuthVO.getAuthSqlList();

		// 类型：1：创建人；2：结算主体；3部门
		List<SysDataAuthMenuRel> menuCreateList = sysDataAuthVO.getMenuCreateList();
		List<SysDataAuthMenuRel> menuSettleList = sysDataAuthVO.getMenuSettleList();
		List<SysDataAuthMenuRel> menuDeptList = sysDataAuthVO.getMenuDeptList();

		// 存储sql的map，用作缓存 键：linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId()
		Map<String, String> authSqlMap = new HashMap<>();
		StringBuilder sql = new StringBuilder();
		String mapSql;
		StringBuilder nowMapSql;
		// Map里的Key
		String linkId = sysDataAuth.getLinkId();
		// 处理权限部门
		if (sysDataAuth.getIsDeptAuth() == 1 || sysDataAuth.getIsDeptAuth() == 2) {
			if (sysDataAuth.getIsDeptAuth() == 2) {
				sql.append(" or dept.dept_id in ('0' ");
				for (SysDataAuthDeptRel dept : authDeptList) {
					sql.append(", '").append(dept.getDeptId()).append("'");
				}
				sql.append(")");
			} else {
				sql.append(" or dept.dept_id = #deptId ");
			}
			for (SysDataAuthMenuRel menu : menuDeptList) {
				authSqlMap.put(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId(), sql.toString());
			}
		}
		String nowSql;
		// 处理创建人
		if (menuCreateList != null && !menuCreateList.isEmpty()) {
			nowSql = " or a.create_by = #create_by ";
			for (SysDataAuthMenuRel menu : menuCreateList) {
				mapSql = authSqlMap.get(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId());
				if (!Common.isEmpty(mapSql)) {
					nowMapSql = new StringBuilder(nowSql).append(mapSql);
				} else {
					nowMapSql = new StringBuilder(nowSql);
				}
				authSqlMap.put(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId(), nowMapSql.toString());
			}
		}

		// 处理结算主体
		if (menuSettleList != null && !menuSettleList.isEmpty()) {
			nowSql = " or a.settle_domain_id in ('0'#settleDomainId) ";
			sysDataAuth.setIsSettleAuth(1);
			for (SysDataAuthMenuRel menu : menuSettleList) {
				mapSql = authSqlMap.get(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId());
				if (!Common.isEmpty(mapSql)) {
					nowMapSql = new StringBuilder(nowSql).append(mapSql);
				} else {
					nowMapSql = new StringBuilder(nowSql);
				}
				authSqlMap.put(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId(), nowMapSql.toString());
			}
		}

		// 处理自定义sql
		if (authSqlList != null && !authSqlList.isEmpty()) {
			List<SysDiySqlMenuRel> menuSqlList;
			for (SysDataAuthDiySql sqls : authSqlList) {
				nowSql = sqls.getDiySql();
				menuSqlList = sqls.getSqlMenuList();
				if (menuSqlList != null && !menuSqlList.isEmpty()) {
					for (SysDiySqlMenuRel menuSql : menuSqlList) {
						mapSql = authSqlMap.get(linkId + CommonConstants.DOWN_LINE_STRING + menuSql.getMenuId());
						if (!Common.isEmpty(mapSql)) {
							nowMapSql = new StringBuilder(nowSql).append(mapSql);
						} else {
							nowMapSql = new StringBuilder(nowSql);
						}
						authSqlMap.put(linkId + CommonConstants.DOWN_LINE_STRING + menuSql.getMenuId(), nowMapSql.toString());
					}
				}
			}
		}

		// 更新缓存
		// 缓存里放入 id_菜单id， sql
		if (!authSqlMap.isEmpty()) {
			// 前缀
			String prefix = " and (1=1 ";
			// 后缀
			String suffix = " ) ";
			for (Map.Entry<String, String> authSql : authSqlMap.entrySet()) {
				cache.put(authSql.getKey(), prefix + authSql.getValue() + suffix);
			}
		}
	}

	/**
	 * @Description: 分页查询
	 * @Author: hgw
	 * @Date: 2022/6/7 14:49
	 * @return: java.util.List<com.yifu.cloud.plus.v1.yifu.admin.api.entity.SysDataAuth>
	 **/
	@Override
	public IPage<SysDataAuth> getSysDataAuthPage(Page<SysDataAuth> page, SysDataAuth sysDataAuth) {
		return baseMapper.getSysDataAuthPage(page, sysDataAuth);
	}

	/**
	 * @Description: 获取list
	 * @Author: hgw
	 * @Date: 2022/6/9 16:47
	 * @return: java.util.List<com.yifu.cloud.plus.v1.yifu.admin.api.entity.SysDataAuth>
	 **/
	@Override
	public List<SysDataAuth> getSysDataAuthList(SysDataAuth sysDataAuth) {
		return baseMapper.getSysDataAuthPage(sysDataAuth);
	}

	/**
	 * @Description: 新增
	 * @Author: hgw
	 * @Date: 2022/6/7 14:48
	 * @return: java.lang.Boolean
	 **/
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<String> saveDataAuth(SysDataAuthVO sysDataAuthVO) {
		YifuUser user = SecurityUtils.getUser();
		if (user == null || Common.isEmpty(user.getId())) {
			return R.failed("请登录！");
		}
		if (sysDataAuthVO != null) {
			SysDataAuth sysDataAuth = sysDataAuthVO.getSysDataAuth();
			// 校验参数
			if (sysDataAuth == null || Common.isEmpty(sysDataAuth.getLinkType())
					|| Common.isEmpty(sysDataAuth.getLinkId()) || Common.isEmpty(sysDataAuth.getLinkName())
					|| Common.isEmpty(sysDataAuth.getIsDeptAuth())) {
				return R.failed("请传参sysDataAuth以及参数！");
			} else {
				List<SysDataAuthMenuRel> saveMenuDeptList = new ArrayList<>();

				// 更新缓存
				Cache cache = cacheManager.getCache(CacheConstants.DATA_AUTH_DETAILS + sysDataAuth.getLinkType());
				if (cache == null) {
					return R.failed("获取Redis缓存失败！");
				}
				// 编辑
				String mainId = sysDataAuth.getId();
				R<String> failed;
				if (mainId == null) {
					SysDataAuth old = new SysDataAuth();
					old.setLinkId(sysDataAuth.getLinkId());
					old.setLinkType(sysDataAuth.getLinkType());
					List<SysDataAuth> oldList = this.getSysDataAuthList(old);
					if (oldList != null && !oldList.isEmpty()) {
						return R.failed(sysDataAuth.getLinkName() + " 已存在，不可新增，请去编辑！");
					}
					// 新增
					sysDataAuth.setCreateBy(user.getId());
					sysDataAuth.setCreateName(user.getNickname());
					sysDataAuth.setCreateTime(LocalDateTime.now());
					if (Common.isEmpty(sysDataAuth.getIsCreateAuth())) {
						sysDataAuth.setIsCreateAuth(0);
					}
					if (Common.isEmpty(sysDataAuth.getIsDeptAuth())) {
						sysDataAuth.setIsDeptAuth(0);
					}
					if (Common.isEmpty(sysDataAuth.getIsSettleAuth())) {
						sysDataAuth.setIsSettleAuth(0);
					}
					if (Common.isEmpty(sysDataAuth.getIsDiySql())) {
						sysDataAuth.setIsDiySql(0);
					}
					this.save(sysDataAuth);
					mainId = sysDataAuth.getId();
				} else {
					sysDataAuth.setUpdateBy(user.getId());
					sysDataAuth.setUpdateTime(LocalDateTime.now());
					// 删除之前的关系
					this.deleteSubInfoByMainId(mainId);
				}
				failed = this.doCore(sysDataAuth, saveMenuDeptList, sysDataAuthVO, mainId, cache);
				if (failed != null) {
					return failed;
				}
				this.updateById(sysDataAuth);

				if (!saveMenuDeptList.isEmpty()) {
					authMenuRelService.saveOrUpdateBatch(saveMenuDeptList);
				}

				return R.ok("保存成功");
			}
		} else {
			return R.failed("请传参sysDataAuthVO！");
		}
	}

	/**
	 * @Description: 核心保存
	 * @Author: hgw
	 * @Date: 2022/6/8 18:41
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	private R<String> doCore(SysDataAuth sysDataAuth, List<SysDataAuthMenuRel> saveMenuDeptList
			, SysDataAuthVO sysDataAuthVO, String mainId, Cache cache) {

		List<SysDataAuthDeptRel> authDeptList = sysDataAuthVO.getAuthDeptList();
		List<SysDataAuthDiySql> authSqlList = sysDataAuthVO.getAuthSqlList();

		// 类型：1：创建人；2：结算主体；3部门
		List<SysDataAuthMenuRel> menuCreateList = sysDataAuthVO.getMenuCreateList();
		List<SysDataAuthMenuRel> menuSettleList = sysDataAuthVO.getMenuSettleList();
		List<SysDataAuthMenuRel> menuDeptList = sysDataAuthVO.getMenuDeptList();

		// 存储sql的map，用作缓存 键：linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId()
		Map<String, String> authSqlMap = new HashMap<>();
		StringBuilder sql = new StringBuilder();
		String mapSql;
		StringBuilder nowMapSql;
		// Map里的Key
		String linkId = sysDataAuth.getLinkId();
		// 处理权限部门
		if (sysDataAuth.getIsDeptAuth() == 1 || sysDataAuth.getIsDeptAuth() == 2) {
			if (menuDeptList == null || menuDeptList.isEmpty()) {
				return R.failed("请选择部门关联的菜单！");
			} else if (sysDataAuth.getIsDeptAuth() == 2) {
				sql.append(" or dept.dept_id in ('0' ");
				for (SysDataAuthDeptRel dept : authDeptList) {
					sql.append(", '").append(dept.getDeptId()).append("'");
					dept.setSysDataAuthId(mainId);
				}
				sql.append(")");
				authDeptRelService.saveOrUpdateBatch(authDeptList);
			} else {
				sql.append(" or dept.dept_id = #deptId ");
			}
			for (SysDataAuthMenuRel menu : menuDeptList) {
				authSqlMap.put(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId(), sql.toString());
				menu.setSysDataAuthId(mainId);
				menu.setType(3);
			}
			saveMenuDeptList.addAll(menuDeptList);
		}
		String nowSql;
		// 处理创建人
		if (menuCreateList != null && !menuCreateList.isEmpty()) {
			nowSql = " or a.create_by = #create_by ";
			sysDataAuth.setIsCreateAuth(1);
			for (SysDataAuthMenuRel menu : menuCreateList) {
				mapSql = authSqlMap.get(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId());
				if (!Common.isEmpty(mapSql)) {
					nowMapSql = new StringBuilder(nowSql).append(mapSql);
				} else {
					nowMapSql = new StringBuilder(nowSql);
				}
				authSqlMap.put(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId(), nowMapSql.toString());
				menu.setType(1);
				menu.setSysDataAuthId(mainId);
			}
			saveMenuDeptList.addAll(menuCreateList);
		}

		// 处理结算主体
		if (menuSettleList != null && !menuSettleList.isEmpty()) {
			nowSql = " or a.settle_domain_id in ('0'#settleDomainId) ";
			sysDataAuth.setIsSettleAuth(1);
			for (SysDataAuthMenuRel menu : menuSettleList) {
				mapSql = authSqlMap.get(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId());
				if (!Common.isEmpty(mapSql)) {
					nowMapSql = new StringBuilder(nowSql).append(mapSql);
				} else {
					nowMapSql = new StringBuilder(nowSql);
				}
				authSqlMap.put(linkId + CommonConstants.DOWN_LINE_STRING + menu.getMenuId(), nowMapSql.toString());
				menu.setType(2);
				menu.setSysDataAuthId(mainId);
			}
			saveMenuDeptList.addAll(menuSettleList);
		}

		// 处理自定义sql
		if (authSqlList != null && !authSqlList.isEmpty()) {
			sysDataAuth.setIsDiySql(1);
			List<SysDiySqlMenuRel> menuSqlList;
			for (SysDataAuthDiySql sqls : authSqlList) {
				nowSql = sqls.getDiySql();
				menuSqlList = sqls.getSqlMenuList();
				if (menuSqlList != null && !menuSqlList.isEmpty()) {
					sqls.setSysDataAuthId(mainId);
					diySqlService.save(sqls);
					for (SysDiySqlMenuRel menuSql : menuSqlList) {
						mapSql = authSqlMap.get(linkId + CommonConstants.DOWN_LINE_STRING + menuSql.getMenuId());
						if (!Common.isEmpty(mapSql)) {
							nowMapSql = new StringBuilder(nowSql).append(mapSql);
						} else {
							nowMapSql = new StringBuilder(nowSql);
						}
						authSqlMap.put(linkId + CommonConstants.DOWN_LINE_STRING + menuSql.getMenuId(), nowMapSql.toString());
						menuSql.setSysDataAuthId(mainId);
						menuSql.setSysDiySqlId(sqls.getId());
					}
					diySqlMenuRelService.saveBatch(menuSqlList);
				} else {
					return R.failed("自定义Sql有内容，要选择菜单！");
				}
			}
		}

		// 更新缓存
		// 缓存里放入 id_菜单id， sql
		if (!authSqlMap.isEmpty()) {
			// 前缀
			String prefix = " and (1=1 ";
			// 后缀
			String suffix = " ) ";
			for (Map.Entry<String, String> authSql : authSqlMap.entrySet()) {
				cache.put(authSql.getKey(), prefix + authSql.getValue() + suffix);
			}
		}
		return null;
	}

	/**
	 * @param mainId 数据权限主表id
	 * @Description: 删除数据权限关联表
	 * @Author: hgw
	 * @Date: 2022/6/9 11:47
	 * @return: void
	 **/
	public void deleteSubInfoByMainId(String mainId) {
		authDeptRelService.deleteAuthDeptRelByAuthId(mainId);
		authMenuRelService.deleteAuthMenuRelByAuthId(mainId);
		diySqlService.deleteDiySqlByAuthId(mainId);
		diySqlMenuRelService.deleteSqlMenuRelByAuthId(mainId);
	}

	/**
	 * 删除
	 *
	 * @param id 部门 ID
	 * @return 成功、失败
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean removeDataAuthById(String id) {
		this.deleteSubInfoByMainId(id);
		this.removeById(id);
		return Boolean.TRUE;
	}

	/**
	 * @param mainId 权限主表id
	 * @Description: 查看
	 * @Author: hgw
	 * @Date: 2022/6/9 14:52
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<com.yifu.cloud.plus.v1.yifu.admin.api.vo.SysDataAuthVO>
	 **/
	@Override
	public R<SysDataAuthVO> getByMainId(String mainId) {
		SysDataAuthVO vo = new SysDataAuthVO();
		SysDataAuth main = this.getById(mainId);
		if (main != null) {
			vo.setSysDataAuth(main);
			// 部门树
			vo.setAuthDeptList(authDeptRelService.getByMainId(mainId));
			// 菜单
			List<SysDataAuthMenuRel> menuList = authMenuRelService.getByMainId(mainId);
			List<SysDataAuthMenuRel> menuCreateList = new ArrayList<>();
			List<SysDataAuthMenuRel> menuSettleList = new ArrayList<>();
			List<SysDataAuthMenuRel> menuDeptList = new ArrayList<>();
			if (menuList != null && !menuList.isEmpty()) {
				for (SysDataAuthMenuRel menu : menuList) {
					switch (menu.getType()) {
						case 1:
							menuCreateList.add(menu);
							break;
						case 2:
							menuSettleList.add(menu);
							break;
						case 3:
							menuDeptList.add(menu);
							break;
						default:
							break;
					}
				}
				vo.setMenuCreateList(menuCreateList);
				vo.setMenuSettleList(menuSettleList);
				vo.setMenuDeptList(menuDeptList);
			}
			// 自定义sql
			List<SysDataAuthDiySql> diyList = diySqlService.getByMainId(mainId);
			if (diyList != null && !diyList.isEmpty()) {
				List<SysDiySqlMenuRel> diyMenuList = diySqlMenuRelService.getByMainId(mainId);
				if (diyMenuList != null && !diyMenuList.isEmpty()) {
					Map<String, List<SysDiySqlMenuRel>> sqlMenuMap = new HashMap<>();
					List<SysDiySqlMenuRel> baseList;
					for (SysDiySqlMenuRel menu : diyMenuList) {
						baseList = sqlMenuMap.get(menu.getSysDiySqlId());
						if (baseList == null) {
							baseList = new ArrayList<>();
						}
						baseList.add(menu);
						sqlMenuMap.put(menu.getSysDiySqlId(), baseList);
					}
					for (SysDataAuthDiySql diy : diyList) {
						if (sqlMenuMap.get(diy.getId()) != null) {
							diy.setSqlMenuList(sqlMenuMap.get(diy.getId()));
						}
					}
				}
				vo.setAuthSqlList(diyList);
			}
			return new R<>(vo);
		} else {
			return R.failed("未找到！");
		}
	}

}
