package admin_menu

import (
	"context"
	"sort"
	"strconv"

	"tydata-server/app/main/api/internal/svc"
	"tydata-server/app/main/api/internal/types"
	"tydata-server/common/ctxdata"
	"tydata-server/common/xerr"

	"github.com/Masterminds/squirrel"
	"github.com/bytedance/sonic"
	"github.com/pkg/errors"
	"github.com/samber/lo"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/mr"
)

type GetMenuAllLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetMenuAllLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMenuAllLogic {
	return &GetMenuAllLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetMenuAllLogic) GetMenuAll(req *types.GetMenuAllReq) (resp *[]types.GetMenuAllResp, err error) {
	userId, err := ctxdata.GetUidFromCtx(l.ctx)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败, %+v", err)
	}

	// 使用MapReduceVoid并发获取用户角色
	var roleIds []int64
	var permissions []*struct {
		RoleId int64
	}

	type UserRoleResult struct {
		RoleId int64
	}

	err = mr.MapReduceVoid(
		func(source chan<- interface{}) {
			adminUserRoleBuilder := l.svcCtx.AdminUserRoleModel.SelectBuilder().Where(squirrel.Eq{"user_id": userId})
			source <- adminUserRoleBuilder
		},
		func(item interface{}, writer mr.Writer[*UserRoleResult], cancel func(error)) {
			builder := item.(squirrel.SelectBuilder)
			result, err := l.svcCtx.AdminUserRoleModel.FindAll(l.ctx, builder, "role_id DESC")
			if err != nil {
				cancel(errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户角色信息失败, %+v", err))
				return
			}

			for _, r := range result {
				writer.Write(&UserRoleResult{RoleId: r.RoleId})
			}
		},
		func(pipe <-chan *UserRoleResult, cancel func(error)) {
			for item := range pipe {
				permissions = append(permissions, &struct{ RoleId int64 }{RoleId: item.RoleId})
			}
		},
	)
	if err != nil {
		return nil, err
	}

	for _, permission := range permissions {
		roleIds = append(roleIds, permission.RoleId)
	}

	// 使用MapReduceVoid并发获取角色菜单
	var menuIds []int64
	var roleMenus []*struct {
		MenuId int64
	}

	type RoleMenuResult struct {
		MenuId int64
	}

	err = mr.MapReduceVoid(
		func(source chan<- interface{}) {
			getRoleMenuBuilder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().Where(squirrel.Eq{"role_id": roleIds})
			source <- getRoleMenuBuilder
		},
		func(item interface{}, writer mr.Writer[*RoleMenuResult], cancel func(error)) {
			builder := item.(squirrel.SelectBuilder)
			result, err := l.svcCtx.AdminRoleMenuModel.FindAll(l.ctx, builder, "id DESC")
			if err != nil {
				cancel(errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取角色菜单信息失败, %+v", err))
				return
			}

			for _, r := range result {
				writer.Write(&RoleMenuResult{MenuId: r.MenuId})
			}
		},
		func(pipe <-chan *RoleMenuResult, cancel func(error)) {
			for item := range pipe {
				roleMenus = append(roleMenus, &struct{ MenuId int64 }{MenuId: item.MenuId})
			}
		},
	)
	if err != nil {
		return nil, err
	}

	for _, roleMenu := range roleMenus {
		menuIds = append(menuIds, roleMenu.MenuId)
	}

	// 使用MapReduceVoid并发获取菜单
	type AdminMenuStruct struct {
		Id        int64
		Pid       int64
		Name      string
		Path      string
		Component string
		Redirect  struct {
			String string
			Valid  bool
		}
		Meta   string
		Sort   int64
		Type   int64
		Status int64
	}

	var menus []*AdminMenuStruct

	err = mr.MapReduceVoid(
		func(source chan<- interface{}) {
			adminMenuBuilder := l.svcCtx.AdminMenuModel.SelectBuilder().Where(squirrel.Eq{"id": menuIds})
			source <- adminMenuBuilder
		},
		func(item interface{}, writer mr.Writer[*AdminMenuStruct], cancel func(error)) {
			builder := item.(squirrel.SelectBuilder)
			result, err := l.svcCtx.AdminMenuModel.FindAll(l.ctx, builder, "sort ASC")
			if err != nil {
				cancel(errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取菜单信息失败, %+v", err))
				return
			}

			for _, r := range result {
				menu := &AdminMenuStruct{
					Id:        r.Id,
					Pid:       r.Pid,
					Name:      r.Name,
					Path:      r.Path,
					Component: r.Component,
					Redirect:  r.Redirect,
					Meta:      r.Meta,
					Sort:      r.Sort,
					Type:      r.Type,
					Status:    r.Status,
				}
				writer.Write(menu)
			}
		},
		func(pipe <-chan *AdminMenuStruct, cancel func(error)) {
			for item := range pipe {
				menus = append(menus, item)
			}
		},
	)
	if err != nil {
		return nil, err
	}

	// 转换为types.Menu结构并存储到映射表
	menuMap := make(map[string]types.GetMenuAllResp)
	for _, menu := range menus {
		// 只处理状态正常的菜单
		if menu.Status != 1 {
			continue
		}

		meta := make(map[string]interface{})
		err = sonic.Unmarshal([]byte(menu.Meta), &meta)
		if err != nil {
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解析菜单Meta信息失败, %+v", err)
		}

		redirect := func() string {
			if menu.Redirect.Valid {
				return menu.Redirect.String
			}
			return ""
		}()

		menuId := strconv.FormatInt(menu.Id, 10)
		menuMap[menuId] = types.GetMenuAllResp{
			Name:      menu.Name,
			Path:      menu.Path,
			Redirect:  redirect,
			Component: menu.Component,
			Sort:      menu.Sort,
			Meta:      meta,
			Children:  make([]types.GetMenuAllResp, 0),
		}
	}

	// 按ParentId将菜单分组
	menuGroups := lo.GroupBy(menus, func(item *AdminMenuStruct) int64 {
		return item.Pid
	})

	// 递归构建菜单树
	var buildMenuTree func(parentId int64) []types.GetMenuAllResp
	buildMenuTree = func(parentId int64) []types.GetMenuAllResp {
		children := make([]types.GetMenuAllResp, 0)

		childMenus, ok := menuGroups[parentId]
		if !ok {
			return children
		}

		// 按Sort排序
		sort.Slice(childMenus, func(i, j int) bool {
			return childMenus[i].Sort < childMenus[j].Sort
		})

		for _, childMenu := range childMenus {
			menuId := strconv.FormatInt(childMenu.Id, 10)
			if menu, exists := menuMap[menuId]; exists && childMenu.Status == 1 {
				// 递归构建子菜单
				menu.Children = buildMenuTree(childMenu.Id)
				children = append(children, menu)
			}
		}

		return children
	}

	// 从根菜单开始构建（ParentId为0的是根菜单）
	menuTree := buildMenuTree(0)

	return &menuTree, nil
}
