package auth

import (
	"testing"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/stretchr/testify/assert"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

func TestBuildMenuTree_RootNodes(t *testing.T) {
	logger, _ := zap.NewDevelopment()
	service := &Service{logger: logger}

	permissions := []*model.Permission{
		{Model: gorm.Model{ID: 1}, PermCode: "user:menu", PermName: "用户管理", URL: "/users", Sort: 1, ParentID: nil},
		{Model: gorm.Model{ID: 2}, PermCode: "order:menu", PermName: "订单管理", URL: "/orders", Sort: 2, ParentID: nil},
		{Model: gorm.Model{ID: 3}, PermCode: "dashboard:menu", PermName: "仪表盘", URL: "/dashboard", Sort: 0, ParentID: nil},
	}

	result := service.buildMenuTree(permissions)

	assert.Len(t, result, 3)
	assert.Equal(t, "dashboard:menu", result[0].PermCode)
	assert.Equal(t, "user:menu", result[1].PermCode)
	assert.Equal(t, "order:menu", result[2].PermCode)
	assert.Empty(t, result[0].Children)
}

func TestBuildMenuTree_MultiLevel(t *testing.T) {
	logger, _ := zap.NewDevelopment()
	service := &Service{logger: logger}

	parentID1 := uint(1)
	parentID2 := uint(3)

	permissions := []*model.Permission{
		{Model: gorm.Model{ID: 1}, PermCode: "user:menu", PermName: "用户管理", URL: "/users", Sort: 1, ParentID: nil},
		{Model: gorm.Model{ID: 2}, PermCode: "user:list:menu", PermName: "用户列表", URL: "/users/list", Sort: 10, ParentID: &parentID1},
		{Model: gorm.Model{ID: 3}, PermCode: "user:role:menu", PermName: "角色管理", URL: "/users/roles", Sort: 5, ParentID: &parentID1},
		{Model: gorm.Model{ID: 4}, PermCode: "user:role:detail:menu", PermName: "角色详情", URL: "/users/roles/detail", Sort: 1, ParentID: &parentID2},
	}

	result := service.buildMenuTree(permissions)

	assert.Len(t, result, 1)
	assert.Equal(t, "user:menu", result[0].PermCode)
	assert.Len(t, result[0].Children, 2)
	assert.Equal(t, "user:role:menu", result[0].Children[0].PermCode)
	assert.Equal(t, "user:list:menu", result[0].Children[1].PermCode)
	assert.Len(t, result[0].Children[0].Children, 1)
	assert.Equal(t, "user:role:detail:menu", result[0].Children[0].Children[0].PermCode)
}

func TestBuildMenuTree_OrphanNodes(t *testing.T) {
	logger, _ := zap.NewDevelopment()
	service := &Service{logger: logger}

	nonExistentParentID := uint(999)

	permissions := []*model.Permission{
		{Model: gorm.Model{ID: 1}, PermCode: "user:menu", PermName: "用户管理", URL: "/users", Sort: 1, ParentID: nil},
		{Model: gorm.Model{ID: 2}, PermCode: "orphan:menu", PermName: "孤儿菜单", URL: "/orphan", Sort: 0, ParentID: &nonExistentParentID},
	}

	result := service.buildMenuTree(permissions)

	assert.Len(t, result, 2)
	assert.Equal(t, "orphan:menu", result[0].PermCode)
	assert.Equal(t, "user:menu", result[1].PermCode)
	assert.Empty(t, result[0].Children)
}

func TestBuildMenuTree_Sorting(t *testing.T) {
	logger, _ := zap.NewDevelopment()
	service := &Service{logger: logger}

	parentID := uint(1)

	permissions := []*model.Permission{
		{Model: gorm.Model{ID: 1}, PermCode: "user:menu", PermName: "用户管理", URL: "/users", Sort: 1, ParentID: nil},
		{Model: gorm.Model{ID: 2}, PermCode: "user:list:menu", PermName: "用户列表", URL: "/users/list", Sort: 10, ParentID: &parentID},
		{Model: gorm.Model{ID: 3}, PermCode: "user:role:menu", PermName: "角色管理", URL: "/users/roles", Sort: 5, ParentID: &parentID},
		{Model: gorm.Model{ID: 4}, PermCode: "user:dept:menu", PermName: "部门管理", URL: "/users/depts", Sort: 8, ParentID: &parentID},
	}

	result := service.buildMenuTree(permissions)

	assert.Len(t, result, 1)
	assert.Len(t, result[0].Children, 3)
	assert.Equal(t, "user:role:menu", result[0].Children[0].PermCode)
	assert.Equal(t, 5, result[0].Children[0].Sort)
	assert.Equal(t, "user:dept:menu", result[0].Children[1].PermCode)
	assert.Equal(t, 8, result[0].Children[1].Sort)
	assert.Equal(t, "user:list:menu", result[0].Children[2].PermCode)
	assert.Equal(t, 10, result[0].Children[2].Sort)
}

func TestBuildMenuTree_EmptyInput(t *testing.T) {
	logger, _ := zap.NewDevelopment()
	service := &Service{logger: logger}

	result := service.buildMenuTree([]*model.Permission{})

	assert.NotNil(t, result)
	assert.Empty(t, result)
}

func TestSortMenuNodes(t *testing.T) {
	logger, _ := zap.NewDevelopment()
	service := &Service{logger: logger}

	nodes := []dto.MenuNode{
		{ID: 3, PermCode: "c", Sort: 30, Children: []dto.MenuNode{}},
		{ID: 1, PermCode: "a", Sort: 10, Children: []dto.MenuNode{}},
		{ID: 2, PermCode: "b", Sort: 20, Children: []dto.MenuNode{}},
	}

	service.sortMenuNodes(nodes)

	assert.Equal(t, "a", nodes[0].PermCode)
	assert.Equal(t, "b", nodes[1].PermCode)
	assert.Equal(t, "c", nodes[2].PermCode)
}
