package rbac

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"

	"security-center-backend/internal/model"
	"security-center-backend/internal/repository"
)

func TestPermissionCatalogIncludesCaasmExportPorts(t *testing.T) {
	perms := PermissionCatalog()
	for _, perm := range perms {
		if perm.Name == "caasm:export_ports" {
			return
		}
	}
	t.Fatal("expected caasm:export_ports to be present in permission catalog")
}

func TestPermissionCatalogIncludesAgentManageOwnKeys(t *testing.T) {
	perms := PermissionCatalog()
	for _, perm := range perms {
		if perm.Name == "agent:manage_own_keys" {
			return
		}
	}
	t.Fatal("expected agent:manage_own_keys to be present in permission catalog")
}

func TestPermissionCatalogIncludesVulnSubmitFindings(t *testing.T) {
	perms := PermissionCatalog()
	for _, perm := range perms {
		if perm.Name == "vuln:submit_findings" {
			return
		}
	}
	t.Fatal("expected vuln:submit_findings to be present in permission catalog")
}

func TestSeedPermissionsGrantsVulnSubmitFindings(t *testing.T) {
	db, err := gorm.Open(sqlite.Open("file:seed-vuln-submit-findings?mode=memory&cache=shared"), &gorm.Config{})
	require.NoError(t, err)
	require.NoError(t, db.AutoMigrate(&model.Role{}, &model.Permission{}))

	permRepo := repository.NewPermissionRepository(db)
	roleRepo := repository.NewRoleRepository(db)
	ctx := context.Background()

	// 预置 admin 与 security_operator 角色，seed 后两者都必须持有 vuln:submit_findings。
	require.NoError(t, roleRepo.Create(ctx, &model.Role{Name: "admin"}))
	require.NoError(t, roleRepo.Create(ctx, &model.Role{Name: "security_operator"}))
	require.NoError(t, SeedPermissions(ctx, permRepo, roleRepo))

	for _, roleName := range []string{"admin", "security_operator"} {
		role, err := roleRepo.FindByName(ctx, roleName)
		require.NoError(t, err)
		names := make([]string, 0, len(role.Permissions))
		for _, perm := range role.Permissions {
			names = append(names, perm.Name)
		}
		require.Contains(t, names, "vuln:submit_findings", "role %s must hold vuln:submit_findings", roleName)
	}
}

func TestSeedPermissionsEnsuresAgentUserRoleIdempotent(t *testing.T) {
	db, err := gorm.Open(sqlite.Open("file:seed-agent-user?mode=memory&cache=shared"), &gorm.Config{})
	require.NoError(t, err)
	require.NoError(t, db.AutoMigrate(&model.Role{}, &model.Permission{}))

	permRepo := repository.NewPermissionRepository(db)
	roleRepo := repository.NewRoleRepository(db)
	ctx := context.Background()

	// 重复执行（模拟多次启动）必须幂等：角色不重复创建、授权不重复。
	require.NoError(t, SeedPermissions(ctx, permRepo, roleRepo))
	require.NoError(t, SeedPermissions(ctx, permRepo, roleRepo))

	var roleCount int64
	require.NoError(t, db.Model(&model.Role{}).Where("name = ?", "agent_user").Count(&roleCount).Error)
	require.Equal(t, int64(1), roleCount)

	role, err := roleRepo.FindByName(ctx, "agent_user")
	require.NoError(t, err)
	require.Len(t, role.Permissions, 1)
	require.Equal(t, "agent:manage_own_keys", role.Permissions[0].Name)
}

func TestSeedPermissionsKeepsExistingAgentUserRole(t *testing.T) {
	db, err := gorm.Open(sqlite.Open("file:seed-agent-user-existing?mode=memory&cache=shared"), &gorm.Config{})
	require.NoError(t, err)
	require.NoError(t, db.AutoMigrate(&model.Role{}, &model.Permission{}))

	permRepo := repository.NewPermissionRepository(db)
	roleRepo := repository.NewRoleRepository(db)
	ctx := context.Background()

	// 预置已存在的 agent_user 角色（如管理员手工建过），seed 不应报错或重建。
	require.NoError(t, roleRepo.Create(ctx, &model.Role{Name: "agent_user", Description: "custom"}))
	require.NoError(t, SeedPermissions(ctx, permRepo, roleRepo))

	var roleCount int64
	require.NoError(t, db.Model(&model.Role{}).Where("name = ?", "agent_user").Count(&roleCount).Error)
	require.Equal(t, int64(1), roleCount)

	role, err := roleRepo.FindByName(ctx, "agent_user")
	require.NoError(t, err)
	require.Equal(t, "custom", role.Description)
	require.Len(t, role.Permissions, 1)
	require.Equal(t, "agent:manage_own_keys", role.Permissions[0].Name)
}
