/*
x *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.system.service.impl;

import static org.springblade.common.constant.CacheConstant.SYS_CACHE;
import static org.springblade.common.constant.TenantConstant.ACCOUNT_NUMBER_KEY;
import static org.springblade.common.constant.TenantConstant.DEFAULT_ACCOUNT_NUMBER;
import static org.springblade.common.constant.TenantConstant.DEFAULT_PASSWORD;
import static org.springblade.common.constant.TenantConstant.PASSWORD_KEY;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import org.springblade.common.cache.ParamCache;
import org.springblade.common.utils.CacheUtil;
import org.springblade.common.utils.DigestUtil;
import org.springblade.common.utils.Number62;
import org.springblade.core.constant.BladeConstant;
import org.springblade.core.constant.RoleConstant;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.exception.ServiceException;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.auth.enums.UserEnum;
import org.springblade.modules.system.entity.CubeGlobalParamType;
import org.springblade.modules.system.entity.CubeWorkspace;
import org.springblade.modules.system.entity.DataPermission;
import org.springblade.modules.system.entity.DataPermissionUser;
import org.springblade.modules.system.entity.Dept;
import org.springblade.modules.system.entity.PermEntity;
import org.springblade.modules.system.entity.PermJsonEntity;
import org.springblade.modules.system.entity.Post;
import org.springblade.modules.system.entity.Role;
import org.springblade.modules.system.entity.SysTenantPackage;
import org.springblade.modules.system.entity.Tenant;
import org.springblade.modules.system.entity.ThirdLoginConfig;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.VisualClassify;
import org.springblade.modules.system.entity.VisualSubscribeNotifyConf;
import org.springblade.modules.system.mapper.TenantMapper;
import org.springblade.modules.system.service.ICubeWorkspaceService;
import org.springblade.modules.system.service.IDeptService;
import org.springblade.modules.system.service.IDictBizService;
import org.springblade.modules.system.service.IMenuService;
import org.springblade.modules.system.service.IPostService;
import org.springblade.modules.system.service.IRoleMenuService;
import org.springblade.modules.system.service.IRoleService;
import org.springblade.modules.system.service.ITenantService;
import org.springblade.modules.system.service.IThirdLoginConfigService;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.service.IVisualClassifyService;
import org.springblade.modules.system.service.VisualSubscribeNotifyConfService;
import org.springblade.modules.system.service.normal.CubeGlobalParamTypeService;
import org.springblade.modules.system.service.normal.DataPermissionService;
import org.springblade.modules.system.service.normal.DataPermissionUserService;
import org.springblade.modules.system.service.normal.SysTenantPackageService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;

/**
 * 服务实现类
 *
 * @author Chill
 */
@Service
@AllArgsConstructor
public class TenantServiceImpl extends BaseServiceImpl<TenantMapper, Tenant> implements ITenantService {

//	private final TenantId tenantId;
	private final IRoleService roleService;
	private final IMenuService menuService;
	private final IDeptService deptService;
	private final IPostService postService;
	private final IRoleMenuService roleMenuService;
	private final IDictBizService dictBizService;
	private final IUserService userService;
	private final SysTenantPackageService tenantPackageService;
	private final DataPermissionService dataPermissionService;
	private final DataPermissionUserService dataPermissionUserService;
	private final IVisualClassifyService visualClassifyService;
	private final ICubeWorkspaceService cubeWorkspaceService;
	private final VisualSubscribeNotifyConfService visualSubscribeNotifyConfService;
	private final IThirdLoginConfigService thirdLoginConfigService;
	private final CubeGlobalParamTypeService cubeGlobalParamTypeService;

	@Override
	public IPage<Tenant> selectTenantPage(IPage<Tenant> page, Tenant tenant) {
		return page.setRecords(baseMapper.selectTenantPage(page, tenant));
	}

	@Override
	public Tenant getByTenantId(String tenantId) {
		return getOne(Wrappers.<Tenant>query().lambda().eq(Tenant::getTenantId, tenantId));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean submitTenant(Tenant tenant) {
		CacheUtil.clear(SYS_CACHE);
		if (Func.isEmpty(tenant.getId())) {
			if(StrUtil.isBlank(tenant.getContactNumber())) {
				throw new ServiceException("租户手机号不能为空");
			}
//			List<Tenant> tenants = baseMapper.selectList(Wrappers.<Tenant>query().lambda().eq(Tenant::getIsDeleted, BladeConstant.DB_NOT_DELETED));
//			List<String> codes = tenants.stream().map(Tenant::getTenantId).collect(Collectors.toList());
//			String tenantId = getTenantId(codes);
			String tenantId = Number62.encode(System.currentTimeMillis());
			tenant.setTenantId(tenantId);
			// 获取参数配置的账号额度
			int accountNumber = Func.toInt(ParamCache.getValue(ACCOUNT_NUMBER_KEY), DEFAULT_ACCOUNT_NUMBER);
			tenant.setAccountNumber(accountNumber);
			// 新建租户套餐关系
			if(StrUtil.isBlank(tenant.getPackageId())) {
				throw new ServiceException("租户套餐不能为空");
			}
			List<SysTenantPackage> tenantPackageList = new ArrayList<>();
			List<Integer> packageIdList = Func.toIntList(tenant.getPackageId());
			packageIdList.forEach(packageId -> tenantPackageList.add(new SysTenantPackage(tenantId, packageId)));
			tenantPackageService.saveBatch(tenantPackageList);
			// 新建租户对应的默认角色
			Role role = new Role();
			role.setTenantId(tenantId);
			role.setParentId(BladeConstant.TOP_PARENT_ID);
			role.setRoleName("管理员");
			role.setRoleAlias(RoleConstant.ADMIN);
			role.setSort(2);
			role.setIsDeleted(BladeConstant.DB_NOT_DELETED);
			roleService.save(role);
			// 新建租户对应的角色菜单权限
//			LinkedList<Menu> userMenus = new LinkedList<>();
			// 获取参数配置的默认菜单集合，逗号隔开
//			List<String> menuCodes = Func.toStrList(ParamCache.getValue(ACCOUNT_MENU_CODE_KEY));
//			List<Menu> menus = getMenus((menuCodes.size() > 0 ? menuCodes : MENU_CODES), userMenus);
//			List<RoleMenu> roleMenus = new ArrayList<>();
//			menus.forEach(menu -> {
//				RoleMenu roleMenu = new RoleMenu();
//				roleMenu.setMenuId(menu.getId());
//				roleMenu.setRoleId(role.getId());
//				roleMenus.add(roleMenu);
//			});
//			roleMenuService.saveBatch(roleMenus);
			// 新建租户对应的默认部门
			Dept dept = new Dept();
			dept.setTenantId(tenantId);
			dept.setParentId(BladeConstant.TOP_PARENT_ID);
			dept.setAncestors(String.valueOf(BladeConstant.TOP_PARENT_ID));
			dept.setDeptName(tenant.getTenantName());
			dept.setFullName(tenant.getTenantName());
			dept.setDeptCategory(1);
			dept.setSort(2);
			dept.setIsDeleted(BladeConstant.DB_NOT_DELETED);
			deptService.save(dept);
			// 新建租户对应的默认岗位
			Post post = new Post();
			post.setTenantId(tenantId);
			post.setCategory(1);
			post.setPostCode("ceo");
			post.setPostName("首席执行官");
			post.setSort(1);
			postService.save(post);
			// 新建租户对应的默认业务字典
//			LinkedList<DictBiz> dictBizs = new LinkedList<>();
//			List<DictBiz> dictBizList = getDictBizs(tenantId, dictBizs);
//			dictBizService.saveBatch(dictBizList);
			//添加超级权限组
			DataPermission dataPermission = new DataPermission();
			dataPermission.setCreateTime(new Date());
			dataPermission.setTenantId(tenantId);
			dataPermission.setSuperStatus(1);
			dataPermission.setTypeId(0);
			List<PermEntity> list = new LinkedList<>();
			List<PermJsonEntity> jsonList = new LinkedList<>();
			PermJsonEntity json = new PermJsonEntity();
			jsonList.add(json);
			PermEntity permEntity = new PermEntity();
			permEntity.setDpList(jsonList);
			permEntity.setUserList(jsonList);
			permEntity.setRoleList(jsonList);
			list.add(permEntity);
			dataPermission.setPermJson(JSONUtil.parseArray(list).toString());
			dataPermission.setCreateUserId(0L);
			dataPermission.setPermName("超级权限组");
			dataPermissionService.save(dataPermission);
			// 新建租户对应的默认管理用户
			User user = new User();
			user.setTenantId(tenantId);
			user.setName("admin");
			user.setRealName("管理员");
			user.setAccount(tenant.getContactNumber());
			user.setPhone(tenant.getContactNumber());
			// 获取参数配置的密码
			String password = Func.toStr(ParamCache.getValue(PASSWORD_KEY), DEFAULT_PASSWORD);
			user.setPassword(password);
			user.setRoleId(String.valueOf(role.getId()));
			user.setDeptId(String.valueOf(dept.getId()));
			user.setPostId(String.valueOf(post.getId()));
			user.setBirthday(new Date());
			user.setSex(1);
			user.setUserType(UserEnum.WEB.getCategory());
			user.setIsDeleted(BladeConstant.DB_NOT_DELETED);
			user.setAuditLevel(1);
			user.setIsLogin(0);
			user.setIsWxLogin(0);
			userService.submit(user);
			tenant.setAdminId(user.getId());
			//把该用户添加到超级权限组中
			DataPermissionUser dataPermissionUser = new DataPermissionUser();
			dataPermissionUser.setUserId(user.getId());
			dataPermissionUser.setDataPermId(dataPermission.getId());
			dataPermissionUser.setUserStatus(1);
			dataPermissionUserService.save(dataPermissionUser);
			// 初始化开放平台配置
			List<VisualSubscribeNotifyConf> notifyConfs = visualSubscribeNotifyConfService.list(Wrappers.<VisualSubscribeNotifyConf>lambdaQuery()
					.eq(VisualSubscribeNotifyConf::getTenantId,"111111"));
			notifyConfs.forEach( conf -> {
				conf.setTenantId(tenantId);
				conf.setId(null);
			});
			visualSubscribeNotifyConfService.saveBatch(notifyConfs);
			// 初始化三方登录配置
			List<ThirdLoginConfig> loginConfigs = thirdLoginConfigService.list(Wrappers.<ThirdLoginConfig>lambdaQuery()
					.eq(ThirdLoginConfig::getTenantId, "111111"));
			loginConfigs.forEach(login -> {
				login.setTenantId(tenantId);
				login.setId(null);
				login.setStatus(1);
			});
			thirdLoginConfigService.saveBatch(loginConfigs);
/***-----------------------BI相关的初始化【未来这块功能放到BI里面，system通过RPC调用初始化】-------------------------------**/
			//创建数据集分类
			List<CubeWorkspace> cubeWorkspaceList = new ArrayList<>();
			String[] values = {"默认", "单表表单", "聚合表单"};
			IntStream.range(0, values.length).forEach(index -> {
				CubeWorkspace workspace = new CubeWorkspace();
				workspace.setSortNum(999 - index);
				workspace.setWsName(values[index]);
				workspace.setCreateBy("系统创建");
				workspace.setCreateTime(new Date());
				workspace.setParentId(0);
				workspace.setCreateUserId(0L);
				workspace.setSystemStatus(1);
				workspace.setTenantId(tenantId);
			});
			cubeWorkspaceService.saveBatch(cubeWorkspaceList);
			//创建大屏分类
			VisualClassify classify = new VisualClassify();
			classify.setTenantId(tenantId);
			classify.setCreateTime(new Date());
			classify.setParentId(0);
			classify.setCreateUserId(0L);
			classify.setCategoryValue("默认");
			visualClassifyService.save(classify);
			// 添加全局参数系统变量
			CubeGlobalParamType cubeGlobalParamType = new CubeGlobalParamType();
			cubeGlobalParamType.setCreateTime(LocalDateTime.now());
			cubeGlobalParamType.setCreateUserId(0L);
			cubeGlobalParamType.setParentId(0);
			cubeGlobalParamType.setTypeName("系统变量");
			cubeGlobalParamType.setSortNum(999);
			cubeGlobalParamType.setTenantId(tenantId);
			cubeGlobalParamTypeService.save(cubeGlobalParamType);
			int globalParmTypeId = cubeGlobalParamType.getId();
			cubeGlobalParamTypeService.insertGlobalParamFromTable(globalParmTypeId, tenantId);
/***-----------------------BI相关的初始化-------------------------------**/
		}else {
			Tenant byId = this.getById(tenant.getId());
			if (!byId.getContactNumber().equals(tenant.getContactNumber())) {
				updateAcountPhone(tenant.getContactNumber(),byId.getContactNumber());
			}
			//不更新以下信息
			tenant.setPackageId(null);
//			tenant.setExpireTime(null);
			tenant.setAccountNumber(null);

		}
		return super.saveOrUpdate(tenant);
	}

	/**
	 * 更新租户账号的手机号
	 */
	private void updateAcountPhone(String newPhone, String phone) {
		if (userService.count(Wrappers.<User>lambdaQuery().eq(User::getPhone, newPhone)) > 0) {
			throw new ServiceException("手机号已存在，请选择手机号");
		}
		User user = new User();
		user.setPhone(newPhone);
		userService.update(user,Wrappers.<User>lambdaQuery().eq(User::getPhone,phone));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean removeTenant(List<Long> ids) {
		CacheUtil.clear(SYS_CACHE);
		List<Tenant> tenantList = this.list(Wrappers.<Tenant>query().lambda().in(Tenant::getId, ids));
		List<String> tenantIds = tenantList.stream().map(tenant -> Func.toStr(tenant.getTenantId())).distinct().collect(Collectors.toList());
		if (tenantIds.contains(BladeConstant.ADMIN_TENANT_ID)) {
			throw new ServiceException("不可删除管理租户!");
		}
		boolean tenantTemp = this.deleteLogic(ids);
		boolean userTemp = userService.remove(Wrappers.<User>query().lambda().in(User::getTenantId, tenantIds));
		return tenantTemp && userTemp;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean setting(Integer accountNumber, Date expireTime, String ids, String packageIds) {
		CacheUtil.clear(SYS_CACHE);
		Func.toLongList(ids).forEach(id -> {
//			Kv kv = Kv.create().set("accountNumber", accountNumber).set("expireTime", expireTime).set("id", id);
//			String licenseKey = DesUtil.encryptToHex(JSON.toJSONString(kv), DES_KEY);
			update(
				Wrappers.<Tenant>update().lambda()
					.set(Tenant::getAccountNumber, accountNumber)
					.set(Tenant::getExpireTime, expireTime)
//					.set(Tenant::getLicenseKey, licenseKey)
					.set(Tenant::getPackageId, packageIds)
					.eq(Tenant::getId, id)
			);
			Tenant tenant = getById(id);
			//删除中间表
			tenantPackageService.remove(Wrappers.<SysTenantPackage>lambdaQuery().eq(SysTenantPackage::getTenantId, tenant.getTenantId()));
			List<SysTenantPackage> tenantPackageList = new ArrayList<>();
			List<Integer> packageIdList = Func.toIntList(packageIds);
			packageIdList.forEach(packageId -> tenantPackageList.add(new SysTenantPackage(tenant.getTenantId(), packageId)));
			tenantPackageService.saveBatch(tenantPackageList);
		});
		return true;
	}

	@Override
	public Boolean updatePassword(String tenantId,String password) {
		if (StrUtil.isEmpty(tenantId)) {
			return false;
		}
		Tenant tenant = this.getByTenantId(tenantId);
		User user = userService.getById(tenant.getAdminId());
		String passwords = DigestUtil.encrypt(password);
		user.setPassword(passwords);

		return userService.updateById(user);
	}

//	private String getTenantId(List<String> codes) {
//		String code = tenantId.generate();
//		if (codes.contains(code)) {
//			return getTenantId(codes);
//		}
//		return code;
//	}

//	private List<Menu> getMenus(List<String> codes, LinkedList<Menu> menus) {
//		codes.forEach(code -> {
//			Menu menu = menuService.getOne(Wrappers.<Menu>query().lambda().eq(Menu::getCode, code).eq(Menu::getIsDeleted, BladeConstant.DB_NOT_DELETED));
//			if (menu != null) {
//				menus.add(menu);
//				recursionMenu(menu.getId(), menus);
//			}
//		});
//		return menus;
//	}
//
//	private void recursionMenu(Long parentId, LinkedList<Menu> menus) {
//		List<Menu> menuList = menuService.list(Wrappers.<Menu>query().lambda().eq(Menu::getParentId, parentId).eq(Menu::getIsDeleted, BladeConstant.DB_NOT_DELETED));
//		menus.addAll(menuList);
//		menuList.forEach(menu -> recursionMenu(menu.getId(), menus));
//	}
//
//	private List<DictBiz> getDictBizs(String tenantId, LinkedList<DictBiz> dictBizs) {
//		List<DictBiz> dictBizList = dictBizService.list(Wrappers.<DictBiz>query().lambda().eq(DictBiz::getParentId, BladeConstant.TOP_PARENT_ID).eq(DictBiz::getIsDeleted, BladeConstant.DB_NOT_DELETED));
//		dictBizList.forEach(dictBiz -> {
//			Long oldParentId = dictBiz.getId();
//			Long newParentId = IdWorker.getId();
//			dictBiz.setId(newParentId);
//			dictBiz.setTenantId(tenantId);
//			dictBizs.add(dictBiz);
//			recursionDictBiz(tenantId, oldParentId, newParentId, dictBizs);
//		});
//		return dictBizs;
//	}
//
//	private void recursionDictBiz(String tenantId, Long oldParentId, Long newParentId, LinkedList<DictBiz> dictBizs) {
//		List<DictBiz> dictBizList = dictBizService.list(Wrappers.<DictBiz>query().lambda().eq(DictBiz::getParentId, oldParentId).eq(DictBiz::getIsDeleted, BladeConstant.DB_NOT_DELETED));
//		dictBizList.forEach(dictBiz -> {
//			Long oldSubParentId = dictBiz.getId();
//			Long newSubParentId = IdWorker.getId();
//			dictBiz.setId(newSubParentId);
//			dictBiz.setTenantId(tenantId);
//			dictBiz.setParentId(newParentId);
//			dictBizs.add(dictBiz);
//			recursionDictBiz(tenantId, oldSubParentId, newSubParentId, dictBizs);
//		});
//	}
}
