package pwc.taxtech.atms.service.impl;

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.common.CommonConstants;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.dao.*;
import pwc.taxtech.atms.dto.MenuDisplayDto;
import pwc.taxtech.atms.dto.MenuDto;
import pwc.taxtech.atms.entity.*;
import pwc.taxtech.atms.exception.ApplicationException;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 *
 */
@Service
public class MenuServiceImpl extends BaseService {

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

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RolePermissionMapper rolePermissionMapper;

    @Autowired
    private PermissionMapper permissionMapper;
    @Resource
    private UserMapper userMapper;

    public List<MenuDisplayDto> getMenusForDisplay(Integer moduleId, String userId) {
        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<String> mendIds = getMenuIds(moduleId, userId);
        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, mendIds);
            if (menuDisplayDto.getSubMenus().size() > 0) {
                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<String> menuIds) {
        List<MenuDisplayDto> subMenuDtos = menus.stream()
                .filter(oneMenu -> menu.getId().equals(oneMenu.getParentId())
                        && CommonConstants.ACTIVE_STATUS.equals(oneMenu.getIsActive())
                        && menuIds.contains(oneMenu.getId()))
                .map(this::rotateMenuToMenuDisplayDto).collect(Collectors.toList());
        menu.setSubMenus(subMenuDtos);
        for (MenuDisplayDto subMenu : subMenuDtos) {
            getSubMenuDto(subMenu, menus, menuIds);
        }
    }

    public List<MenuDto> getFilterMenus(Integer moduleId, String userId) {
        List<String> menuIds = getMenuIds(moduleId, userId);
        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);
            iteratorMenu2(menus, menuDto, menuIds);
        }

        menuDtos = menuDtos.stream().filter(menuDto -> menuDto.getSubMenus().size() > 0).collect(Collectors.toList());

        return menuDtos;

    }
    private List<String> getMenuIds(Integer moduleId, String userId) {
        //fix superAdmin 返回所有权限
        userId = authUserHelper.getCurrentUserId();
        if (!StringUtils.hasText(userId)) {
            return Collections.emptyList();
        }
        User user = userMapper.selectByPrimaryKey(userId)
;
        if (user == null) {
            return Collections.emptyList();
        }

        if (user.getIsSuperAdmin()) {
            return permissionMapper.selectByExample(null).stream().map(Permission::getMenuId)
                    .collect(Collectors.toList());
        } else {
            UserRoleExample userRoleExample = new UserRoleExample();
            userRoleExample.createCriteria().andUserIdEqualTo(userId);
            List<String> userRoleIdList = userRoleMapper.selectByExample(userRoleExample).stream().map(UserRole::getRoleId).collect(Collectors.toList());
            List<String> permissionIds = rolePermissionMapper.selectByRoleId(userRoleIdList.get(0))
                    .stream().map(RolePermission::getPermissionId).collect(Collectors.toList());
            PermissionExample permissionExample = new PermissionExample();
            permissionExample.createCriteria().andIdIn(permissionIds);
            List<String> menuIds = permissionMapper.selectByExample(permissionExample)
                    .stream().map(Permission::getMenuId).collect(Collectors.toList());
            //        List<MenuDto> menus = getMenus(moduleId).stream().filter(x -> permissionNames.contains(x.getName())).collect(Collectors.toList());
            return menuIds;
        }
    }

    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);
            }
        }
    }

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

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

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

}