package packs

import (
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	permfeatures "github.com/nexuscrm/backend/internal/features/permissions"
	"github.com/nexuscrm/backend/internal/infrastructure/persistence"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestInitializePermissions_HotPathCountsByProfileID(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock.New() error = %v", err)
	}
	defer db.Close()

	mock.ExpectQuery(`SELECT .* FROM .*UserRole.*WHERE .*IsDeleted.*`).
		WillReturnRows(sqlmock.NewRows([]string{"Id", "Name", "RollupDescription", "ParentRoleId"}))

	repo := persistence.NewPermissionRepository(db)
	permSvc := permfeatures.NewPermissionService(repo, nil, nil)

	// GetAllProfiles query — returns the 2 bootstrap profiles
	profileIDs := []string{
		constants.ProfileSystemAdmin,
		constants.ProfileStandardUser,
	}
	profileRows := sqlmock.NewRows([]string{"Id", "Name", "Description", "IsSystem"})
	for _, pid := range profileIDs {
		profileRows.AddRow(pid, pid, "", true)
	}
	mock.ExpectQuery(`SELECT .* FROM .*Profile.* ORDER BY`).
		WillReturnRows(profileRows)

	// BulkEnsureProfilePermissionSets — single SELECT returning all 2 permission sets
	psRows := sqlmock.NewRows([]string{"ProfileId", "Id", "IsDeleted"})
	for _, pid := range profileIDs {
		psRows.AddRow(pid, "ps_"+pid, 0)
	}
	mock.ExpectQuery(`SELECT .* FROM .PermissionSet. WHERE .ProfileId. IN`).
		WillReturnRows(psRows)

	// BulkCountObjectPermissionsByProfiles — single GROUP BY query returning counts
	countRows := sqlmock.NewRows([]string{"ProfileId", "COUNT(*)"})
	for _, pid := range profileIDs {
		countRows.AddRow(pid, 10)
	}
	mock.ExpectQuery(`SELECT .* COUNT\(\*\) FROM .ObjectPermissions. .* JOIN .PermissionSet.`).
		WillReturnRows(countRows)

	if err := InitializePermissions(permSvc, nil); err != nil {
		t.Fatalf("InitializePermissions() error = %v", err)
	}

	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("unmet SQL expectations: %v", err)
	}
}

func TestBuildBusinessPermissionSeedScope(t *testing.T) {
	scope := buildBusinessPermissionSeedScope([]*models.ObjectMetadata{
		{
			APIName:  "Account",
			IsSystem: false,
			Fields: []models.FieldMetadata{
				{APIName: "Name"},
				{APIName: "OwnerId"},
			},
		},
		{
			APIName:  constants.TableUser,
			IsSystem: false,
			Fields: []models.FieldMetadata{
				{APIName: "Name"},
			},
		},
		{
			APIName:  constants.TablePermission,
			IsSystem: true,
			Fields: []models.FieldMetadata{
				{APIName: "APIName"},
			},
		},
		{
			APIName:  "OpportunityContactRole",
			IsSystem: false,
			Fields: []models.FieldMetadata{
				{APIName: "OpportunityId"},
				{APIName: "ContactId"},
			},
			AccessPolicy: &models.ObjectAccessPolicy{Mode: "derived"},
		},
		{
			APIName: "_System_CustomThing",
			Fields: []models.FieldMetadata{
				{APIName: "Name"},
			},
		},
	})

	if got, want := len(scope.schemas), 2; got != want {
		t.Fatalf("len(scope.schemas) = %d, want %d", got, want)
	}
	if got, want := scope.expectedObjectRowsPerProfile, 2; got != want {
		t.Fatalf("expectedObjectRowsPerProfile = %d, want %d", got, want)
	}
	if got, want := scope.expectedFieldRowsPerProfile, 3; got != want {
		t.Fatalf("expectedFieldRowsPerProfile = %d, want %d", got, want)
	}
}

func TestProfilesNeedingPermissionReconcile(t *testing.T) {
	scope := permissionSeedScope{
		expectedObjectRowsPerProfile: 2,
		expectedFieldRowsPerProfile:  5,
	}

	candidates := profilesNeedingPermissionReconcile(
		[]string{"p1", "p2", "p3"},
		map[string]int{"p1": 2, "p2": 1, "p3": 2},
		map[string]int{"p1": 5, "p2": 5, "p3": 4},
		scope,
	)

	if got, want := len(candidates), 2; got != want {
		t.Fatalf("len(candidates) = %d, want %d", got, want)
	}
	if candidates[0] != "p2" || candidates[1] != "p3" {
		t.Fatalf("unexpected candidates: %#v", candidates)
	}
}
