package com.eactive.eai.rms.common.acl.sitemap;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode;
import com.eactive.eai.rms.common.base.BaseService;
import com.eactive.eai.rms.data.entity.man.menu.Menu;
import com.eactive.eai.rms.data.entity.man.menu.MenuService;
import com.eactive.eai.rms.data.entity.man.role.RoleMenuAuthService;

@Service("sitemapService")
@Transactional(transactionManager = "transactionManagerForEMS")
public class SitemapServiceImpl extends BaseService implements SitemapService {

	@Autowired
	private MenuService menuService;

	@Autowired
	private RoleMenuAuthService roleMenuAuthService;

	public List<SitemapNode> getSitemapTree(String serviceType) {
		Menu root = menuService.getById("ROOT_DEV");
		Menu langRoot = findLangRoot(root);
		List<SitemapNode> tree = new ArrayList<>();
		if (langRoot == null) {
			return tree;
		}

		Set<String> serviceTypeMenuIds = StringUtils.isBlank(serviceType)
				? null
				: new HashSet<>(roleMenuAuthService.findMenuIdsByServiceType(serviceType));

		for (Menu menu : sortedChildren(langRoot)) {
			if (isVisible(menu) && matchesServiceType(menu, serviceTypeMenuIds)) {
				tree.add(buildNode(menu, serviceTypeMenuIds));
			}
		}
		return tree;
	}

	// 엔티티의 childMenus는 menuId 기준으로 정렬되어 있어, 실제 메뉴(운영화면 GNB)와 동일하게 sortOrder 기준으로 재정렬한다.
	private List<Menu> sortedChildren(Menu menu) {
		List<Menu> children = new ArrayList<>(menu.getChildMenus());
		children.sort(Comparator.comparing(Menu::getSortOrder, Comparator.nullsLast(Comparator.naturalOrder())));
		return children;
	}

	// MenuService.getMenuList()의 GNB 렌더링과 동일하게 "ROOT"(한글)/"ROOT_EN"(영문) 이름의 언어별 루트를 찾는다.
	private Menu findLangRoot(Menu root) {
		String lang = LocaleContextHolder.getLocale().getLanguage();
		String langRootName = (StringUtils.isBlank(lang) || "ko".equalsIgnoreCase(lang))
				? "ROOT"
				: "ROOT_" + lang.toUpperCase();

		return root.getChildMenus().stream()
				.filter(m -> langRootName.equalsIgnoreCase(m.getMenuName()))
				.findFirst()
				.orElse(null);
	}

	private SitemapNode buildNode(Menu menu, Set<String> serviceTypeMenuIds) {
		SitemapNode node = new SitemapNode(menu);
		for (Menu child : sortedChildren(menu)) {
			if (isVisible(child) && matchesServiceType(child, serviceTypeMenuIds)) {
				node.getChildren().add(buildNode(child, serviceTypeMenuIds));
			}
		}
		return node;
	}

	private boolean isVisible(Menu menu) {
		return "Y".equalsIgnoreCase(menu.getDisplayYn()) && "Y".equalsIgnoreCase(menu.getUseYn());
	}

	// serviceType 필터가 없으면 통과. 있으면 자신이나 하위메뉴 중 하나라도 해당 serviceType 권한이 있어야 통과(상위메뉴 누락 방지).
	private boolean matchesServiceType(Menu menu, Set<String> serviceTypeMenuIds) {
		if (serviceTypeMenuIds == null) {
			return true;
		}
		if (serviceTypeMenuIds.contains(menu.getMenuId())) {
			return true;
		}
		return menu.getChildMenus().stream().anyMatch(child -> matchesServiceType(child, serviceTypeMenuIds));
	}

}
