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.CollectionUtils;
import org.springframework.util.StringUtils;
import pwc.taxtech.atms.common.CommonConstants;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.dao.MenuMapper;
import pwc.taxtech.atms.dao.PermissionMapper;
import pwc.taxtech.atms.dao.RolePermissionMapper;
import pwc.taxtech.atms.dao.UserRoleMapper;
import pwc.taxtech.atms.dto.MenuDisplayDto;
import pwc.taxtech.atms.dto.MenuDto;
import pwc.taxtech.atms.dto.navtree.DevTreeDto;
import pwc.taxtech.atms.entity.*;
import pwc.taxtech.atms.exception.ApplicationException;

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

/**
 */
@Service
public class MenuServiceImpl {

    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;

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

    }

    private List<String> getMenuIds(Integer moduleId,String userId){
        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());
        // admin权限暂时不做控制
        if(moduleId==1){
            menuIds.add("91223c21-c15a-4882-89cc-42f3807ec9e3");
            menuIds.add("9bf855fb-6b44-49cd-b95b-41a6a9a8c098");
            menuIds.add("F9A18F3A-7E39-4661-BA00-F149710577C3");
            menuIds.add("F9A18F3A-7E39-4661-BA00-F149710577C4");
            menuIds.add("F9A18F3A-7E39-4661-BA00-F149710577C7");
        }else if(moduleId==3){
            // 这里的权限之后需要在数据库中加上对应的权限数据
            menuIds.add("6b404066-2200-4d11-9436-d0870dfd3188");
            menuIds.add("6b404066-2200-4d11-9436-d0870dfd3189");
            menuIds.add("5bdbc9a7-197b-43cc-b0e6-3f50e41b13eb");
            menuIds.add("5bdbc9a7-197b-43cc-b0e6-3f50e41b13ec");
            menuIds.add("5bdbc9a7-197b-43cc-b0e6-3f50e41b13eg");
            menuIds.add("5bdbc9a7-197b-43cc-b0e6-3f50e41b13eh");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0813");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0814");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0815");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0816");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0817");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0818");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0819");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0820");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0821");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0822");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0823");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0824");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0825");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0826");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0827");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0828");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0829");
            menuIds.add("a9b1cd87-89ef-4dae-b798-b19e9bbe0830");
            menuIds.add("b8c74ee9-e5d7-467b-8565-e77efe6a499f");
        }else if(moduleId==4){
            // 这里的权限之后需要在数据库中加上对应的权限数据
            menuIds.add("12776533-9c54-4737-a28c-0cd2a3d75047");
            menuIds.add("12776533-9c54-4737-a28c-0cd2a3d75048");
            menuIds.add("12776533-9c54-4737-a28c-0cd2a3d75049");
            menuIds.add("17d6cd83-f5b6-46f2-88e0-58d21957ad29");
            menuIds.add("17d6cd83-f5b6-46f2-88e0-58d21957ad30");
        }
        //        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);
    }

}