package pwc.taxtech.atms.service.impl;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import pwc.taxtech.atms.exception.ApplicationException;
import pwc.taxtech.atms.common.CommonConstants;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.dao.MenuMapper;
import pwc.taxtech.atms.dto.MenuDisplayDto;
import pwc.taxtech.atms.dto.MenuDto;
import pwc.taxtech.atms.entity.Menu;
import pwc.taxtech.atms.entity.MenuExample;
import pwc.taxtech.atms.service.MenuService;

/**
 */
@Service
public class MenuServiceImpl implements MenuService {

    private static final Logger logger = LoggerFactory.getLogger(MenuServiceImpl.class);

    @Autowired
    private MenuMapper menuMapper;

    @Override
    public List<MenuDisplayDto> getMenusForDisplay(Integer moduleId) {
        logger.debug("Start to get menus for display");
        if (moduleId == null) {
            throw new ApplicationException("serviceId for getMenusForDisplay can't be null");
        }
        List<MenuDisplayDto> menuDisplayDtos = new ArrayList<>();
        List<Menu> menus = findByServiceTypeId(moduleId);
        List<Menu> rootNodes = menus.stream().filter(oneMenu -> !StringUtils.hasText(oneMenu.getParentId()))
                .collect(Collectors.toList());
        for (Menu menu : rootNodes) {
            // 把EF获取的menu转化为Dto形式
            MenuDisplayDto menuDisplayDto = rotateMenuToMenuDisplayDto(menu);
            getSubMenuDto(menuDisplayDto, menus);
            menuDisplayDtos.add(menuDisplayDto);
        }
        return menuDisplayDtos;
    }

    private MenuDisplayDto rotateMenuToMenuDisplayDto(Menu menu) {
        MenuDisplayDto menuDisplayDto = new MenuDisplayDto();
        CommonUtils.copyProperties(menu, menuDisplayDto);
        return menuDisplayDto;
    };

    private MenuDto rotateMenuToMenuDto(Menu menu) {
        MenuDto menuDto = new MenuDto();
        CommonUtils.copyProperties(menu, menuDto);
        return menuDto;
    };

    private void getSubMenuDto(MenuDisplayDto menu, List<Menu> menus) {
        List<MenuDisplayDto> subMenuDtos = menus.stream()
                .filter(oneMenu -> menu.getId().equals(oneMenu.getParentId())
                        && CommonConstants.ACTIVE_STATUS.equals(oneMenu.getIsActive()))
                .map(this::rotateMenuToMenuDisplayDto).collect(Collectors.toList());
        menu.setSubMenus(subMenuDtos);
        for (MenuDisplayDto subMenu : subMenuDtos) {
            getSubMenuDto(subMenu, menus);
        }
    }

    @Override
    public List<MenuDto> getMenus(Integer moduleId) {
        logger.debug("Start to get menus");
        if (moduleId == null) {
            throw new ApplicationException("serviceId for getMenus can't be null");
        }
        List<MenuDto> menuDtos = new ArrayList<>();
        List<Menu> menus = findByServiceTypeId(moduleId);
        for (Menu menu : menus) {
            MenuDto menuDto = rotateMenuToMenuDto(menu);
            if (!StringUtils.hasText(menu.getParentId())) {
                menuDtos.add(menuDto);
            }
            List<MenuDto> subMenuDtos = menus.stream().filter(oneMenu -> menu.getId().equals(oneMenu.getParentId()))
                    .map(this::rotateMenuToMenuDto).collect(Collectors.toList());
            menuDto.setSubMenus(subMenuDtos);
            iteratorMenu(menus, menuDto);
        }
        return menuDtos;
    }

    private List<Menu> findByServiceTypeId(Integer moduleId) {
        MenuExample menuExample = new MenuExample();
        menuExample.createCriteria().andServiceTypeIdEqualTo(moduleId.toString());
        menuExample.setOrderByClause("ORDER_INDEX ASC");
        return menuMapper.selectByExample(menuExample);
    }

    private void iteratorMenu(List<Menu> menus, MenuDto menu) {
        List<Menu> subMenus = menus.stream().filter(oneMenu -> menu.getId().equals(oneMenu.getParentId()))
                .collect(Collectors.toList());
        if (!subMenus.isEmpty()) {
            List<MenuDto> subMenuDtos = subMenus.stream().map(this::rotateMenuToMenuDto).collect(Collectors.toList());
            menu.setSubMenus(subMenuDtos);
            for (MenuDto m : subMenuDtos) {
                iteratorMenu(menus, m);
            }
        }
    }

    @Override
    public List<Menu> findByIsActive(Boolean isActive) {
        MenuExample menuExample = new MenuExample();
        menuExample.createCriteria().andIsActiveEqualTo(isActive);
        return menuMapper.selectByExample(menuExample);
    }

    @Override
    public void update(Menu menu) {
        menuMapper.updateByPrimaryKeySelective(menu);
    }

}