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/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"
)

func createContextWithUserType(userID uint, userType int) context.Context {
	return middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:       userID,
		UserType:     userType,
		ShopID:       0,
		EnterpriseID: 0,
		CustomerID:   0,
	})
}

func TestPermissionService_CheckPermission_SuperAdmin(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

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

	t.Run("超级管理员自动拥有所有权限", func(t *testing.T) {
		ctx := createContextWithUserType(1, constants.UserTypeSuperAdmin)

		hasPermission, err := service.CheckPermission(ctx, 1, "any:permission", constants.PlatformAll)
		require.NoError(t, err)
		assert.True(t, hasPermission)
	})
}

func TestPermissionService_CheckPermission_NormalUser(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

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

	ctx := createContextWithUserType(100, constants.UserTypePlatform)

	perm1 := &model.Permission{
		PermName:              "用户创建",
		PermCode:              "user:create",
		PermType:              constants.PermissionTypeButton,
		Platform:              constants.PlatformAll,
		AvailableForRoleTypes: "1",
		Status:                constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err := permStore.Create(ctx, perm1)
	require.NoError(t, err)

	perm2 := &model.Permission{
		PermName:              "用户查看",
		PermCode:              "user:view",
		PermType:              constants.PermissionTypeButton,
		Platform:              constants.PlatformWeb,
		AvailableForRoleTypes: "1",
		Status:                constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err = permStore.Create(ctx, perm2)
	require.NoError(t, err)

	role := &model.Role{
		RoleName: "测试角色",
		RoleDesc: "测试用角色",
		RoleType: constants.RoleTypePlatform,
		Status:   constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err = roleStore.Create(ctx, role)
	require.NoError(t, err)

	accountRole := &model.AccountRole{
		AccountID: 100,
		RoleID:    role.ID,
		Status:    constants.StatusEnabled,
		Creator:   1,
		Updater:   1,
	}
	err = accountRoleStore.Create(ctx, accountRole)
	require.NoError(t, err)

	rolePerm1 := &model.RolePermission{
		RoleID: role.ID,
		PermID: perm1.ID,
		Status: constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err = rolePermStore.Create(ctx, rolePerm1)
	require.NoError(t, err)

	rolePerm2 := &model.RolePermission{
		RoleID: role.ID,
		PermID: perm2.ID,
		Status: constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err = rolePermStore.Create(ctx, rolePerm2)
	require.NoError(t, err)

	t.Run("有权限的用户应返回true", func(t *testing.T) {
		hasPermission, err := service.CheckPermission(ctx, 100, "user:create", constants.PlatformAll)
		require.NoError(t, err)
		assert.True(t, hasPermission)
	})

	t.Run("无权限的用户应返回false", func(t *testing.T) {
		hasPermission, err := service.CheckPermission(ctx, 100, "user:delete", constants.PlatformAll)
		require.NoError(t, err)
		assert.False(t, hasPermission)
	})

	t.Run("platform为all的权限在web端可访问", func(t *testing.T) {
		hasPermission, err := service.CheckPermission(ctx, 100, "user:create", constants.PlatformWeb)
		require.NoError(t, err)
		assert.True(t, hasPermission)
	})

	t.Run("platform为web的权限在h5端不可访问", func(t *testing.T) {
		hasPermission, err := service.CheckPermission(ctx, 100, "user:view", constants.PlatformH5)
		require.NoError(t, err)
		assert.False(t, hasPermission)
	})

	t.Run("platform为web的权限在web端可访问", func(t *testing.T) {
		hasPermission, err := service.CheckPermission(ctx, 100, "user:view", constants.PlatformWeb)
		require.NoError(t, err)
		assert.True(t, hasPermission)
	})
}

func TestPermissionService_CheckPermission_NoRole(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

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

	t.Run("用户无角色应返回false", func(t *testing.T) {
		ctx := createContextWithUserType(200, constants.UserTypePlatform)

		hasPermission, err := service.CheckPermission(ctx, 200, "any:permission", constants.PlatformAll)
		require.NoError(t, err)
		assert.False(t, hasPermission)
	})
}

func TestPermissionService_CheckPermission_RoleNoPermission(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

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

	ctx := createContextWithUserType(300, constants.UserTypePlatform)

	role := &model.Role{
		RoleName: "空角色",
		RoleDesc: "无权限的角色",
		RoleType: constants.RoleTypePlatform,
		Status:   constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err := roleStore.Create(ctx, role)
	require.NoError(t, err)

	accountRole := &model.AccountRole{
		AccountID: 300,
		RoleID:    role.ID,
		Status:    constants.StatusEnabled,
		Creator:   1,
		Updater:   1,
	}
	err = accountRoleStore.Create(ctx, accountRole)
	require.NoError(t, err)

	t.Run("角色无权限应返回false", func(t *testing.T) {
		hasPermission, err := service.CheckPermission(ctx, 300, "any:permission", constants.PlatformAll)
		require.NoError(t, err)
		assert.False(t, hasPermission)
	})
}
