
package org.springblade.modules.system.service;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springblade.common.cache.ParamCache;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.auth.provider.UserType;
import org.springblade.modules.system.pojo.entity.*;
import org.springblade.modules.system.rule.TenantContext;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import static org.springblade.common.constant.TenantConstant.*;

/**
 * 租户流程编排服务 (替代 LiteFlow tenantChain)
 *
 * 原 LiteFlow 流程:
 * THEN(
 *   tenantRule,
 *   WHEN(tenantRoleRule, tenantRoleMenuRule, tenantDeptRule, tenantPostRule, tenantDictBizRule, tenantUserRule)
 * )
 *
 * @author Chill
 */
@Service
@AllArgsConstructor
public class TenantChainService {

	/**
	 * 执行租户初始化流程
	 *
	 * @param tenantContext 租户上下文
	 * @return TenantContext
	 */
	public TenantContext execute(TenantContext tenantContext) {
		try {
			// 1. tenantRule - 租户基础信息构建
			tenantProcess(tenantContext);

			// 2. WHEN(...) - 并行构建各业务对象 (实际上这些逻辑互不依赖,可以并行)
			// 但为了简化,这里按顺序执行
			tenantRoleProcess(tenantContext);
			tenantRoleMenuProcess(tenantContext);
			tenantDeptProcess(tenantContext);
			tenantPostProcess(tenantContext);
			tenantDictBizProcess(tenantContext);
			tenantUserProcess(tenantContext);

			return tenantContext;
		} catch (Exception e) {
			throw new ServiceException("租户业务数据构建异常");
		}
	}

	/**
	 * tenantRule - 租户构建
	 */
	private void tenantProcess(TenantContext tenantContext) {
		Tenant tenant = tenantContext.getTenant();
		ITenantService tenantService = tenantContext.getTenantService();

		// 获取租户ID
		List<Tenant> tenants = tenantService.list(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(tenantContext.getTenantIdGenerator(), codes);
		tenant.setTenantId(tenantId);

		// 获取参数配置的账号额度
		int accountNumber = Func.toInt(ParamCache.getValue(ACCOUNT_NUMBER_KEY), DEFAULT_ACCOUNT_NUMBER);
		tenant.setAccountNumber(accountNumber);

		tenantContext.setTenant(tenant);
	}

	/**
	 * tenantRoleRule - 租户角色构建
	 */
	private void tenantRoleProcess(TenantContext tenantContext) {
		Tenant tenant = tenantContext.getTenant();

		// 新建租户对应的默认角色
		Role role = new Role();
		role.setTenantId(tenant.getTenantId());
		role.setParentId(BladeConstant.TOP_PARENT_ID);
		role.setRoleName("管理员");
		role.setRoleAlias("admin");
		role.setSort(2);
		role.setIsDeleted(BladeConstant.DB_NOT_DELETED);

		tenantContext.setRole(role);
	}

	/**
	 * tenantRoleMenuRule - 租户角色菜单构建
	 */
	private void tenantRoleMenuProcess(TenantContext tenantContext) {
		IMenuService menuService = tenantContext.getMenuService();

		// 新建租户对应的角色菜单权限
		LinkedList<Menu> userMenus = new LinkedList<>();
		// 获取参数配置的默认菜单集合,逗号隔开
		List<String> menuCodes = Func.toStrList(ParamCache.getValue(ACCOUNT_MENU_CODE_KEY));
		List<Menu> menus = getMenus(menuService, (!menuCodes.isEmpty() ? menuCodes : MENU_CODES), userMenus);
		List<RoleMenu> roleMenuList = new ArrayList<>();
		menus.forEach(menu -> {
			RoleMenu roleMenu = new RoleMenu();
			roleMenu.setMenuId(menu.getId());
			roleMenuList.add(roleMenu);
		});

		tenantContext.setRoleMenuList(roleMenuList);
	}

	/**
	 * tenantDeptRule - 租户机构构建
	 */
	private void tenantDeptProcess(TenantContext tenantContext) {
		Tenant tenant = tenantContext.getTenant();

		// 新建租户对应的默认部门
		Dept dept = new Dept();
		dept.setTenantId(tenant.getTenantId());
		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);

		tenantContext.setDept(dept);
	}

	/**
	 * tenantPostRule - 租户岗位构建
	 */
	private void tenantPostProcess(TenantContext tenantContext) {
		Tenant tenant = tenantContext.getTenant();

		// 新建租户对应的默认岗位
		Post post = new Post();
		post.setTenantId(tenant.getTenantId());
		post.setCategory(1);
		post.setPostCode("ceo");
		post.setPostName("首席执行官");
		post.setSort(1);

		tenantContext.setPost(post);
	}

	/**
	 * tenantDictBizRule - 租户业务字典构建
	 */
	private void tenantDictBizProcess(TenantContext tenantContext) {
		Tenant tenant = tenantContext.getTenant();
		IDictBizService dictBizService = tenantContext.getDictBizService();

		// 新建租户对应的默认业务字典
		LinkedList<DictBiz> dictBizs = new LinkedList<>();
		List<DictBiz> dictBizList = getDictBizs(dictBizService, tenant.getTenantId(), dictBizs);

		tenantContext.setDictBizList(dictBizList);
	}

	/**
	 * tenantUserRule - 租户用户构建
	 */
	private void tenantUserProcess(TenantContext tenantContext) {
		Tenant tenant = tenantContext.getTenant();

		// 新建租户对应的默认管理用户
		User user = new User();
		user.setTenantId(tenant.getTenantId());
		user.setName("admin");
		user.setRealName("admin");
		user.setAccount("admin");
		// 获取参数配置的密码
		String password = Func.toStr(ParamCache.getValue(PASSWORD_KEY), DEFAULT_PASSWORD);
		user.setPassword(password);
		user.setBirthday(new Date());
		user.setSex(1);
		user.setUserType(UserType.WEB.getCategory());
		user.setIsDeleted(BladeConstant.DB_NOT_DELETED);

		tenantContext.setUser(user);
	}

	// ========== 辅助方法 ==========

	private String getTenantId(org.springblade.core.tenant.TenantId tenantIdGenerator, List<String> codes) {
		String code = tenantIdGenerator.generate();
		if (codes.contains(code)) {
			return getTenantId(tenantIdGenerator, codes);
		}
		return code;
	}

	private List<Menu> getMenus(IMenuService menuService, 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(menuService, menu.getId(), menus);
			}
		});
		return menus;
	}

	private void recursionMenu(IMenuService menuService, 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(menuService, menu.getId(), menus));
	}

	private List<DictBiz> getDictBizs(IDictBizService dictBizService, String tenantId, LinkedList<DictBiz> dictBizs) {
		List<DictBiz> dictBizList = dictBizService.list(Wrappers.<DictBiz>query().lambda()
			.eq(DictBiz::getParentId, BladeConstant.TOP_PARENT_ID)
			.eq(DictBiz::getTenantId, BladeConstant.ADMIN_TENANT_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(dictBizService, tenantId, oldParentId, newParentId, dictBizs);
		});
		return dictBizs;
	}

	private void recursionDictBiz(IDictBizService dictBizService, 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(dictBizService, tenantId, oldSubParentId, newSubParentId, dictBizs);
		});
	}
}
