package unit

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/internal/service/permission"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
)

// TestPermissionPlatformFilter_List 测试权限列表按 platform 过滤
func TestPermissionPlatformFilter_List(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	permissionStore := postgres.NewPermissionStore(tx)
	accountRoleStore := postgres.NewAccountRoleStore(tx, rdb)
	rolePermStore := postgres.NewRolePermissionStore(tx, rdb)
	service := permission.New(permissionStore, accountRoleStore, rolePermStore, rdb)

	ctx := context.Background()
	ctx = middleware.SetUserContext(ctx, middleware.NewSimpleUserContext(1, constants.UserTypeSuperAdmin, 0))

	baseReq := &dto.PermissionListRequest{Page: 1, PageSize: 1000}
	_, existingTotal, err := service.List(ctx, baseReq)
	require.NoError(t, err)

	allReq := &dto.PermissionListRequest{Page: 1, PageSize: 1000, Platform: constants.PlatformAll}
	_, existingAllTotal, err := service.List(ctx, allReq)
	require.NoError(t, err)

	webReq := &dto.PermissionListRequest{Page: 1, PageSize: 1000, Platform: constants.PlatformWeb}
	_, existingWebTotal, err := service.List(ctx, webReq)
	require.NoError(t, err)

	h5Req := &dto.PermissionListRequest{Page: 1, PageSize: 1000, Platform: constants.PlatformH5}
	_, existingH5Total, err := service.List(ctx, h5Req)
	require.NoError(t, err)

	permissions := []*model.Permission{
		{PermName: "全端菜单_test", PermCode: "menu:all:test", PermType: constants.PermissionTypeMenu, Platform: constants.PlatformAll, Status: constants.StatusEnabled},
		{PermName: "Web菜单_test", PermCode: "menu:web:test", PermType: constants.PermissionTypeMenu, Platform: constants.PlatformWeb, Status: constants.StatusEnabled},
		{PermName: "H5菜单_test", PermCode: "menu:h5:test", PermType: constants.PermissionTypeMenu, Platform: constants.PlatformH5, Status: constants.StatusEnabled},
		{PermName: "Web按钮_test", PermCode: "button:web:test", PermType: constants.PermissionTypeButton, Platform: constants.PlatformWeb, Status: constants.StatusEnabled},
		{PermName: "H5按钮_test", PermCode: "button:h5:test", PermType: constants.PermissionTypeButton, Platform: constants.PlatformH5, Status: constants.StatusEnabled},
	}
	for _, perm := range permissions {
		require.NoError(t, tx.Create(perm).Error)
	}

	t.Run("查询全部权限", func(t *testing.T) {
		req := &dto.PermissionListRequest{Page: 1, PageSize: 1000}
		_, total, err := service.List(ctx, req)
		require.NoError(t, err)
		assert.Equal(t, existingTotal+5, total)
	})

	t.Run("只查询all端口权限", func(t *testing.T) {
		req := &dto.PermissionListRequest{Page: 1, PageSize: 1000, Platform: constants.PlatformAll}
		perms, total, err := service.List(ctx, req)
		require.NoError(t, err)
		assert.Equal(t, existingAllTotal+1, total)
		found := false
		for _, perm := range perms {
			if perm.PermName == "全端菜单_test" {
				found = true
				break
			}
		}
		assert.True(t, found, "应包含测试创建的全端菜单权限")
	})

	t.Run("只查询web端口权限", func(t *testing.T) {
		req := &dto.PermissionListRequest{Page: 1, PageSize: 1000, Platform: constants.PlatformWeb}
		perms, total, err := service.List(ctx, req)
		require.NoError(t, err)
		assert.Equal(t, existingWebTotal+2, total)
		for _, perm := range perms {
			assert.Equal(t, constants.PlatformWeb, perm.Platform)
		}
	})

	t.Run("只查询h5端口权限", func(t *testing.T) {
		req := &dto.PermissionListRequest{Page: 1, PageSize: 1000, Platform: constants.PlatformH5}
		perms, total, err := service.List(ctx, req)
		require.NoError(t, err)
		assert.Equal(t, existingH5Total+2, total)
		for _, perm := range perms {
			assert.Equal(t, constants.PlatformH5, perm.Platform)
		}
	})
}

// TestPermissionPlatformFilter_CreateWithDefaultPlatform 测试创建权限时默认 platform 为 all
func TestPermissionPlatformFilter_CreateWithDefaultPlatform(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	permissionStore := postgres.NewPermissionStore(tx)
	accountRoleStore := postgres.NewAccountRoleStore(tx, rdb)
	rolePermStore := postgres.NewRolePermissionStore(tx, rdb)
	service := permission.New(permissionStore, accountRoleStore, rolePermStore, rdb)

	ctx := context.Background()
	ctx = middleware.SetUserContext(ctx, middleware.NewSimpleUserContext(1, constants.UserTypeSuperAdmin, 0))

	// 创建权限时不指定 platform
	req := &dto.CreatePermissionRequest{
		PermName: "测试权限",
		PermCode: "test:permission",
		PermType: constants.PermissionTypeMenu,
		// Platform 字段为空
	}

	perm, err := service.Create(ctx, req)
	require.NoError(t, err)
	assert.Equal(t, constants.PlatformAll, perm.Platform, "未指定 platform 时应默认为 all")
}

// TestPermissionPlatformFilter_CreateWithSpecificPlatform 测试创建权限时指定 platform
func TestPermissionPlatformFilter_CreateWithSpecificPlatform(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	permissionStore := postgres.NewPermissionStore(tx)
	accountRoleStore := postgres.NewAccountRoleStore(tx, rdb)
	rolePermStore := postgres.NewRolePermissionStore(tx, rdb)
	service := permission.New(permissionStore, accountRoleStore, rolePermStore, rdb)

	ctx := context.Background()
	ctx = middleware.SetUserContext(ctx, middleware.NewSimpleUserContext(1, constants.UserTypeSuperAdmin, 0))

	tests := []struct {
		name     string
		platform string
		expected string
	}{
		{name: "指定为all", platform: constants.PlatformAll, expected: constants.PlatformAll},
		{name: "指定为web", platform: constants.PlatformWeb, expected: constants.PlatformWeb},
		{name: "指定为h5", platform: constants.PlatformH5, expected: constants.PlatformH5},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req := &dto.CreatePermissionRequest{
				PermName: "测试权限_" + tt.platform,
				PermCode: "test:" + tt.platform,
				PermType: constants.PermissionTypeMenu,
				Platform: tt.platform,
			}

			perm, err := service.Create(ctx, req)
			require.NoError(t, err)
			assert.Equal(t, tt.expected, perm.Platform)
		})
	}
}

// TestPermissionPlatformFilter_Tree 测试权限树包含 platform 字段
func TestPermissionPlatformFilter_Tree(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	permissionStore := postgres.NewPermissionStore(tx)
	accountRoleStore := postgres.NewAccountRoleStore(tx, rdb)
	rolePermStore := postgres.NewRolePermissionStore(tx, rdb)
	service := permission.New(permissionStore, accountRoleStore, rolePermStore, rdb)

	ctx := context.Background()
	ctx = middleware.SetUserContext(ctx, middleware.NewSimpleUserContext(1, constants.UserTypeSuperAdmin, 0))

	existingTree, err := service.GetTree(ctx, nil)
	require.NoError(t, err)
	existingCount := len(existingTree)

	parent := &model.Permission{
		PermName: "系统管理_tree_test",
		PermCode: "system:manage:tree_test",
		PermType: constants.PermissionTypeMenu,
		Platform: constants.PlatformWeb,
		Status:   constants.StatusEnabled,
	}
	require.NoError(t, tx.Create(parent).Error)

	child := &model.Permission{
		PermName: "用户管理_tree_test",
		PermCode: "user:manage:tree_test",
		PermType: constants.PermissionTypeMenu,
		Platform: constants.PlatformWeb,
		ParentID: &parent.ID,
		Status:   constants.StatusEnabled,
	}
	require.NoError(t, tx.Create(child).Error)

	tree, err := service.GetTree(ctx, nil)
	require.NoError(t, err)
	assert.Len(t, tree, existingCount+1)

	var testRoot *dto.PermissionTreeNode
	for _, node := range tree {
		if node.PermName == "系统管理_tree_test" {
			testRoot = node
			break
		}
	}
	require.NotNil(t, testRoot, "应包含测试创建的父节点")
	assert.Equal(t, constants.PlatformWeb, testRoot.Platform)

	require.Len(t, testRoot.Children, 1)
	childNode := testRoot.Children[0]
	assert.Equal(t, "用户管理_tree_test", childNode.PermName)
	assert.Equal(t, constants.PlatformWeb, childNode.Platform)
}
