package service

import (
	"iot_manager_service/app/system/dao"
	"iot_manager_service/app/system/model"
	"iot_manager_service/util/common"
	"sort"
)

var MenuService = new(menuService)

type menuService struct{}

func (s *menuService) Get(id int64) (*dao.Menu, error) {
	menu := &dao.Menu{
		ID: id,
	}
	err := menu.Get()
	if err != nil {
		return nil, err
	}
	return menu, nil
}

func (s *menuService) Submit(req dao.Menu) *common.Errors {
	role := &req
	if role.ID == 0 {
		err := role.Save()
		if err != nil {
			return common.FailResponse(err.Error(), nil)
		}
		return common.SuccessResponse(common.Succeeded, nil)
	}
	err := role.Update()
	if err != nil {
		return common.FailResponse(err.Error(), nil)
	}
	return common.SuccessResponse(common.Succeeded, nil)
}

func (s *menuService) GetAll() []dao.Menu {
	menu := &dao.Menu{}
	menus, err := menu.GetAll()
	if err != nil {
		return nil
	}
	return menus
}

func (s *menuService) Tree() ([]model.MenuRouteDetail, error) {
	allMenus := s.GetAll()
	var rsp []model.MenuRouteDetail
	//上级角色——多个下级角色数组
	tmp := make(map[int64][]dao.Menu)
	for _, menu := range allMenus {
		childes, isExist := tmp[menu.ParentId]
		if isExist {
			childes = append(childes, menu)
			tmp[menu.ParentId] = childes
		} else {
			tmp[menu.ParentId] = []dao.Menu{menu}
		}
	}

	if len(tmp) == 0 {
		return nil, nil
	}
	roots, _ := tmp[0]
	rsp = menuDfs(rsp, roots, tmp)

	return rsp, nil
}

func (s *menuService) Routes(roleId int64) ([]model.MenuRouteDetail, error) {
	allMenus := s.GetAll()
	menuMap := make(map[int64]dao.Menu)
	for _, menu := range allMenus {
		menuMap[menu.ID] = menu
	}

	roleMenus := RoleMenuService.GetMenuByRole(roleId)
	var rsp []model.MenuRouteDetail
	//上级角色——多个下级角色数组
	tmp := make(map[int64][]dao.Menu)
	for _, roleMenu := range roleMenus {
		if menu, isExist := menuMap[roleMenu.MenuId]; isExist {
			childes, isExist := tmp[menu.ParentId]
			if isExist {
				childes = append(childes, menu)
				tmp[menu.ParentId] = childes
			} else {
				tmp[menu.ParentId] = []dao.Menu{menu}
			}
		}

	}

	if len(tmp) == 0 {
		return nil, nil
	}
	roots, _ := tmp[0]
	rsp = menuDfs(rsp, roots, tmp)
	sort.Slice(rsp, func(i, j int) bool {
		if rsp[i].Sort < rsp[j].Sort {
			return true
		}
		return false
	})
	return rsp, nil
}

func menuDfs(result []model.MenuRouteDetail, menus []dao.Menu, tmp map[int64][]dao.Menu) []model.MenuRouteDetail {
	if len(menus) == 0 {
		return nil
	}
	for _, child := range menus {
		detail := model.MenuRouteDetail{}
		detail.Menu = child
		childes, isExist := tmp[child.ID]
		if isExist {
			detail.HasChildren = true
			detail.Children = menuDfs([]model.MenuRouteDetail{}, childes, tmp)
			result = append(result, detail)
		} else {
			detail.HasChildren = false
			result = append(result, detail)
		}
	}
	return result
}

func (s *menuService) LazyList(parentId int64, name, code, alias string) ([]model.MenuLazyListDetail, error) {
	menu := &dao.Menu{
		ParentId: parentId,
		Name:     name,
		Code:     code,
		Alias:    alias,
	}
	menus, err := menu.GetByParentId()
	if err != nil {
		return nil, err
	}
	var parentIds []int64
	for _, m := range menus {
		parentIds = append(parentIds, m.ID)
	}
	hasChildrenMap, err := menu.HasChildren(parentIds)
	if err != nil {
		return nil, err
	}
	var rsp []model.MenuLazyListDetail
	for _, m := range menus {
		hasChildren := hasChildrenMap[m.ID]
		rsp = append(rsp, model.MenuLazyListDetail{
			Menu:        m,
			HasChildren: hasChildren,
		})
	}
	return rsp, nil
}

func (s *menuService) GetTree() ([]model.MenuRouteDetail, error) {
	menuDao := dao.Menu{ParentId: int64(0)}
	var menuDetails []model.MenuRouteDetail
	var temp model.MenuRouteDetail

	//所有菜单包装为菜单详情
	menus, err := menuDao.GetAll()
	var allDetails []model.MenuRouteDetail
	for _, v := range menus {
		temp.Menu = v
		allDetails = append(allDetails, temp)
	}
	//一级菜单 parent_id为0 包装为菜单详情
	lv1s, _ := menuDao.GetByParentId()
	for _, v := range lv1s {
		temp.Menu = v
		temp.Children, temp.HasChildren = s.getChildren(temp, allDetails)
		menuDetails = append(menuDetails, temp)
	}
	return menuDetails, err
}

func (s *menuService) getChildren(parent model.MenuRouteDetail,
	all []model.MenuRouteDetail) ([]model.MenuRouteDetail, bool) {
	id := parent.ID
	var children []model.MenuRouteDetail
	for _, detail := range all {
		if detail.ParentId == id {
			detail.Children, detail.HasChildren = s.getChildren(detail, all)
			children = append(children, detail)
		}
	}
	return children, children != nil
}