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

import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.rms.common.acl.menu.ui.MenuUI;
import com.eactive.eai.rms.common.acl.menu.ui.MenuUISearch;
import com.eactive.eai.rms.common.acl.user.RecordAuthUtil;
import com.eactive.eai.rms.common.base.BaseService;
import com.eactive.eai.rms.common.login.SessionManager;
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.onl.common.exception.BizException;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

@Service("menuManService")
@Transactional(transactionManager = "transactionManagerForEMS")
public class MenuManServiceImpl extends BaseService implements MenuManService {

	@Autowired
	private MenuUIMapper menuUIMapper;

	@Autowired
	private MenuService menuService;

	public List<MenuUI> selectTree(MenuUISearch menuUISearch) {
		List<Menu> menu = findRootMenuTree();
		List<MenuUI> menuUI = new ArrayList<>();
		for(Menu menus : menu) {
			buildMenuTree(menus, menuUI, -1, menuUISearch);
		}
		return menuUI;
	}

	private List<Menu> findRootMenuTree() {
		Menu menu = menuService.getById("ROOT_DEV");
		return new ArrayList<>(menu.getChildMenus());
	}

	private void buildMenuTree(Menu menu, List<MenuUI> list, int level, MenuUISearch menuUISearch) {
		final Integer currentLevel = level + 1;
		boolean isSearchActive = StringUtils.isNotBlank(menuUISearch.getSearchName())
										|| StringUtils.isNotBlank(menuUISearch.getSearchUrl())
										|| StringUtils.isNotBlank(menuUISearch.getSearchId())
										|| StringUtils.isNotBlank(menuUISearch.getSearchParent());

		MenuUI menuUI = new MenuUI(menu, currentLevel, isSearchActive);

		if (isContains(menu, menuUISearch)) {
			list.add(menuUI);
		}
		menu.getChildMenus().forEach(m -> buildMenuTree(m, list, currentLevel, menuUISearch));

	}

	private boolean isContains(Menu menu, MenuUISearch menuUISearch) {
		if (StringUtils.isBlank(menuUISearch.getSearchName())
			&& StringUtils.isBlank(menuUISearch.getSearchUrl())
			&& StringUtils.isBlank(menuUISearch.getSearchId())
			&& StringUtils.isBlank(menuUISearch.getSearchParent())) {
			return true;
		}

		boolean matchName	= matches(menu.getMenuName(), menuUISearch.getSearchName());
		boolean matchUrl 		= matches(menu.getMenuUrl(), menuUISearch.getSearchUrl());
		boolean matchId 		= matches(menu.getMenuId(), menuUISearch.getSearchId());
		boolean matchParent	= matches(menu.getParentMenuId(), menuUISearch.getSearchParent());

		return matchName && matchUrl && matchId && matchParent 
				|| menu.getChildMenus().stream()
					.anyMatch(m -> isContains(m, menuUISearch));
	}

	private boolean matches(String value, String searchValue) {
		return StringUtils.isBlank(searchValue) || StringUtils.containsIgnoreCase(value, searchValue);
	}

	public void insert(MenuUI menuUI) { 
		if (menuService.existsById(menuUI.getMenuId())) {
			throw new BizException("중복된 메뉴 ID가 존재합니다.");
		}
		menuUI.setMenuName(StringEscapeUtils.unescapeHtml(menuUI.getMenuName()));
		Menu menu = menuUIMapper.toEntity(menuUI);
		menu.setParentMenu(menuService.findById(menuUI.getParentMenuId()).orElse(null));
		menu.getParentMenu().getChildMenus().add(menu);
		menuService.save(menu);
	}

	public void update(MenuUI menuUI) {
		Menu menu = menuService.getById(menuUI.getMenuId());
		menuUIMapper.updateToEntity(menuUI, menu);
		menu.setMenuName(StringEscapeUtils.unescapeHtml(menuUI.getMenuName()));
		menuService.save(menu);
	}

	public void delete(String menuId) {
		Menu menu = menuService.getById(menuId);
		menu.getParentMenu().getChildMenus().remove(menu);
		menuService.deleteById(menuId);
	}

	public String getPosition(HttpServletRequest request) throws Exception {
		return RecordAuthUtil.getPosition(request.getParameter("menuId"));
	}

	public String getMenuName(HttpServletRequest request) throws Exception {
		MenuService menuService = ApplicationContextProvider.getContext().getBean(MenuService.class);
		return menuService.getMenuName(request.getParameter("menuId"));
	}

	/**
	 * 현재 메뉴 에 대한 권한 정보 얻어오기 ( W:readWrite, R:readOnly )
	 */
	public String getMenuAuth(HttpServletRequest request) throws Exception {
		String menuId = request.getParameter("menuId");
      String serviceType = request.getParameter("serviceType");
		String userId = SessionManager.getUserId(request);
      return RecordAuthUtil.getMenuAuth(request, userId, menuId, serviceType);
	}

	public Page<MenuUI> selectDbList(Pageable pageable, MenuUISearch menuUISearch) {
		Page<Menu> page = menuService.findAll(pageable, menuUISearch);
		return page.map(menuUIMapper::toVo);
	}

}