package tests

import (
	"context"
	"testing"

	"github.com/veypi/vbase/auth"
)

func TestScopedAuth(t *testing.T) {
	ensureUsers(t)

	ctx := context.Background()

	// 1. Test Scoped Permission Assignment
	t.Run("Scoped Permission Assignment", func(t *testing.T) {
		scope := "test_scope_1"
		testAuth := auth.Factory.New(scope)

		// Grant 'resource:read' to User1 in test_scope
		permID := "resource:read"
		level := auth.LevelRead

		if err := testAuth.Grant(ctx, User1ID, permID, level); err != nil {
			t.Fatalf("Failed to grant permission: %v", err)
		}

		// Verify Check within the same scope
		if !testAuth.Check(ctx, User1ID, permID, level) {
			t.Errorf("Expected User1 to have %s in %s scope", permID, scope)
		}
	})

	// 2. Test Hierarchy (Admin Inheritance vs Normal Strictness)
	t.Run("Hierarchy Checks", func(t *testing.T) {
		scope := "test_scope_2"
		testAuth := auth.Factory.New(scope)

		// Case A: Normal Level (Read) - Exact Match Only
		// Grant "project:p1" (Read)
		if err := testAuth.Grant(ctx, User1ID, "project:p1", auth.LevelRead); err != nil {
			t.Fatal(err)
		}

		// Check Exact Match -> Should Pass
		if !testAuth.Check(ctx, User1ID, "project:p1", auth.LevelRead) {
			t.Error("Exact match 'project:p1' failed")
		}

		// Check Child "project:p1:task:t1" -> Should Fail (Normal levels don't inherit downwards)
		if testAuth.Check(ctx, User1ID, "project:p1:task:t1", auth.LevelRead) {
			t.Error("Normal level 'project:p1' should NOT imply 'project:p1:task:t1'")
		}

		// Case B: Admin Level - Downward Inheritance
		// Grant "org:o1" (Admin)
		if err := testAuth.Grant(ctx, User1ID, "org:o1", auth.LevelAdmin); err != nil {
			t.Fatal(err)
		}

		// Check Child "org:o1:project:p2" -> Should Pass
		if !testAuth.Check(ctx, User1ID, "org:o1:project:p2", auth.LevelRead) {
			t.Error("Admin level 'org:o1' SHOULD imply 'org:o1:project:p2'")
		}

		// Check Wildcard "*" (Admin)
		if err := testAuth.Grant(ctx, User1ID, "*", auth.LevelAdmin); err != nil {
			t.Fatal(err)
		}
		// Should have access to everything
		if !testAuth.Check(ctx, User1ID, "anything:anywhere", auth.LevelAdmin) {
			t.Error("Wildcard '*' should grant access to everything")
		}
	})

	// 3. Test ListResources
	t.Run("ListResources", func(t *testing.T) {
		scope := "test_scope_3"
		testAuth := auth.Factory.New(scope)

		// Setup:
		// User1 has:
		// - project:p1 (Read)
		// - project:p2:task:t1 (Write) -> Should imply project:p2 (Read)
		// - project:p3 (Admin)

		testAuth.Grant(ctx, User1ID, "project:p1", auth.LevelRead)
		testAuth.Grant(ctx, User1ID, "project:p2:task:t1", auth.LevelWrite)
		testAuth.Grant(ctx, User1ID, "project:p3", auth.LevelAdmin)

		resources, err := testAuth.ListResources(ctx, User1ID, "project")
		if err != nil {
			t.Fatalf("ListResources failed: %v", err)
		}

		// Check p1
		if l, ok := resources["p1"]; !ok || l != auth.LevelRead {
			t.Errorf("Expected p1: %d, got %v", auth.LevelRead, l)
		}

		// Check p2 (Implication from child)
		if l, ok := resources["p2"]; !ok || l != auth.LevelRead {
			t.Errorf("Expected p2: %d (implied read), got %v", auth.LevelRead, l)
		}

		// Check p3
		if l, ok := resources["p3"]; !ok || l != auth.LevelAdmin {
			t.Errorf("Expected p3: %d, got %v", auth.LevelAdmin, l)
		}
	})

	// 4. Test ListUsers
	t.Run("ListUsers", func(t *testing.T) {
		scope := "test_scope_4"
		testAuth := auth.Factory.New(scope)

		// Setup:
		// User1 has group:g1:project:p1 (Read)
		// User2 has group:g1:project:p1 (Admin)
		// User3 has group:g1 (Admin) -> Parent Admin (Valid even depth)
		// User4 has group:g1:project:p1:task:t1 (Read) -> Child

		testAuth.Grant(ctx, User1ID, "group:g1:project:p1", auth.LevelRead)
		testAuth.Grant(ctx, User2ID, "group:g1:project:p1", auth.LevelAdmin)
		testAuth.Grant(ctx, AdminID, "group:g1", auth.LevelAdmin) // Parent (depth 2)
		testAuth.Grant(ctx, "user4", "group:g1:project:p1:task:t1", auth.LevelRead)

		users, err := testAuth.ListUsers(ctx, "group:g1:project:p1")
		if err != nil {
			t.Fatalf("ListUsers failed: %v", err)
		}

		if users[User1ID] != auth.LevelRead {
			t.Errorf("Expected User1: Read, got %v", users[User1ID])
		}
		if users[User2ID] != auth.LevelAdmin {
			t.Errorf("Expected User2: Admin, got %v", users[User2ID])
		}
		if users[AdminID] != auth.LevelAdmin {
			t.Errorf("Expected Admin: Admin (inherited), got %v", users[AdminID])
		}
		if _, ok := users["user4"]; ok {
			t.Error("User4 should NOT appear in ListUsers('group:g1:project:p1')")
		}
	})
}
