package tests

import (
	"testing"

	"github.com/veypi/vbase/cfg"
	"github.com/veypi/vbase/models"
)

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

	var roleID string

	// Test 1: List Roles (as admin)
	t.Run("List Roles", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/roles", nil, AdminToken)
		assertStatus(t, resp, 200)

		var data struct {
			Items []struct {
				ID   string `json:"id"`
				Code string `json:"code"`
				Name string `json:"name"`
			} `json:"items"`
		}
		decodeResponse(t, resp, &data)
		t.Logf("Total roles: %d", len(data.Items))

		if len(data.Items) == 0 {
			t.Errorf("Expected some roles, got 0")
		}
	})

	// Test 2: Create Role
	t.Run("Create Role", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/roles", map[string]string{
			"code":        "test_role",
			"name":        "Test Role",
			"description": "Role created for testing",
		}, AdminToken)
		assertStatus(t, resp, 200)

		var data struct {
			ID string `json:"id"`
		}
		decodeResponse(t, resp, &data)
		roleID = data.ID
		t.Logf("Created role: %s", roleID)
	})

	if roleID == "" {
		t.Fatal("Failed to create role, skipping remaining tests")
	}

	// Test 3: Get Role Details
	t.Run("Get Role Details", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/roles/"+roleID, nil, AdminToken)
		assertStatus(t, resp, 200)

		var data struct {
			Code string `json:"code"`
			Name string `json:"name"`
		}
		decodeResponse(t, resp, &data)

		if data.Code != "test_role" {
			t.Errorf("Expected code 'test_role', got '%s'", data.Code)
		}
		if data.Name != "Test Role" {
			t.Errorf("Expected name 'Test Role', got '%s'", data.Name)
		}
	})

	// Test 4: Update Role
	t.Run("Update Role", func(t *testing.T) {
		resp := doRequest(t, "PATCH", "/api/roles/"+roleID, map[string]string{
			"name":        "Updated Test Role",
			"description": "Updated description",
		}, AdminToken)
		assertStatus(t, resp, 200)

		// Verify update
		resp = doRequest(t, "GET", "/api/roles/"+roleID, nil, AdminToken)
		assertStatus(t, resp, 200)

		var data struct {
			Name string `json:"name"`
		}
		decodeResponse(t, resp, &data)

		if data.Name != "Updated Test Role" {
			t.Errorf("Expected name 'Updated Test Role', got '%s'", data.Name)
		}
	})

	// Test 5: Get Role Permissions
	t.Run("Get Role Permissions", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/roles/"+roleID+"/permissions", nil, AdminToken)
		assertStatus(t, resp, 200)

		// Returns array directly
		var data []struct {
			ID string `json:"id"`
		}
		decodeResponse(t, resp, &data)
		t.Logf("Role permissions count: %d", len(data))
	})

	// Test 6: Update Role Permissions
	t.Run("Update Role Permissions", func(t *testing.T) {
		// First, get available permissions
		resp := doRequest(t, "GET", "/api/roles", nil, AdminToken)
		assertStatus(t, resp, 200)

		// Try to update with an empty permission list first
		resp = doRequest(t, "PUT", "/api/roles/"+roleID+"/permissions", map[string]interface{}{
			"permission_ids": []string{},
		}, AdminToken)
		assertStatus(t, resp, 200)
		t.Logf("Updated role permissions to empty")
	})

	// Test 7: Delete Role
	t.Run("Delete Role", func(t *testing.T) {
		resp := doRequest(t, "DELETE", "/api/roles/"+roleID, nil, AdminToken)
		assertStatus(t, resp, 200)

		// Verify deletion
		resp = doRequest(t, "GET", "/api/roles/"+roleID, nil, AdminToken)
		if resp.Code == 200 {
			t.Errorf("Expected role to be deleted, but got 200")
		} else {
			t.Logf("Role deleted successfully, got code: %d", resp.Code)
		}
	})
}

// Test role access control
func TestRoleAccessControl(t *testing.T) {
	ensureUsers(t)

	// Ensure User1 has NO role permissions
	cfg.DB().Where("user_id = ?", User1ID).Delete(&models.Permission{})

	// Regular user tries to access role endpoints - should fail (admin only)
	t.Run("Regular User List Roles", func(t *testing.T) {
		resp := doRequest(t, "GET", "/api/roles", nil, User1Token)
		// Should fail - role:read requires admin permission
		if resp.Code == 200 {
			t.Errorf("Expected regular user to be denied, got 200")
		} else {
			t.Logf("Regular user correctly denied list roles, code: %d", resp.Code)
		}
	})

	t.Run("Regular User Create Role", func(t *testing.T) {
		resp := doRequest(t, "POST", "/api/roles", map[string]string{
			"code":        "illegal_role",
			"name":        "Should Fail",
			"description": "Should not be created",
		}, User1Token)
		// Should fail - needs role:create permission
		if resp.Code == 200 {
			t.Errorf("Expected regular user to be denied, got 200")
		} else {
			t.Logf("Regular user correctly denied create role, code: %d", resp.Code)
		}
	})
}

// Test system role protection
func TestSystemRoleProtection(t *testing.T) {
	ensureUsers(t)

	// Try to modify system role (admin)
	t.Run("Update System Role", func(t *testing.T) {
		resp := doRequest(t, "PATCH", "/api/roles/admin", map[string]string{
			"name": "Hacked Admin",
		}, AdminToken)
		// Should fail - system roles are protected
		if resp.Code == 200 {
			t.Errorf("Expected system role update to be denied, got 200")
		} else {
			t.Logf("System role correctly protected, code: %d", resp.Code)
		}
	})

	t.Run("Update System Role Permissions", func(t *testing.T) {
		resp := doRequest(t, "PUT", "/api/roles/admin/permissions", map[string]interface{}{
			"permission_ids": []string{},
		}, AdminToken)
		// Should fail - system roles are protected
		if resp.Code == 200 {
			t.Errorf("Expected system role permissions update to be denied, got 200")
		} else {
			t.Logf("System role permissions correctly protected, code: %d", resp.Code)
		}
	})

	t.Run("Delete System Role", func(t *testing.T) {
		resp := doRequest(t, "DELETE", "/api/roles/admin", nil, AdminToken)
		// Should fail - system roles cannot be deleted
		if resp.Code == 200 {
			t.Errorf("Expected system role deletion to be denied, got 200")
		} else {
			t.Logf("System role deletion correctly protected, code: %d", resp.Code)
		}
	})
}
