package service

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"gorm.io/gorm"
)

func TestUserGroupService_Create_InvalidParentID(t *testing.T) {
	mockRepo := new(MockUserGroupRepository)
	mockTenantRepo := new(MockTenantRepository)
	mockKeto := new(MockKetoServiceShared)
	mockOutbox := new(MockKetoOutboxRepositoryShared)
	svc := NewUserGroupService(mockRepo, nil, mockTenantRepo, mockKeto, mockOutbox, nil)

	tenantID := "company-1"
	invalidParentID := "invalid-uuid"
	name := "Invalid Parent Group"
	description := ""
	unitType := "Team"

	// Mock: TenantRepo returns record not found for invalidParentID
	mockTenantRepo.On("FindByID", mock.Anything, invalidParentID).Return(nil, gorm.ErrRecordNotFound).Once()

	// No Create calls should happen on any repo if parent is invalid
	mockRepo.AssertNotCalled(t, "Create")
	mockTenantRepo.AssertNotCalled(t, "Create")
	mockOutbox.AssertNotCalled(t, "Create")

	group, err := svc.Create(context.Background(), tenantID, &invalidParentID, name, description, unitType)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "parent tenant not found or invalid")
	assert.Nil(t, group)

	mockTenantRepo.AssertExpectations(t)
}

func TestUserGroupService_AddMember_GroupNotFound(t *testing.T) {
	mockOutbox := new(MockKetoOutboxRepositoryShared)
	mockUserGroupRepo := new(MockUserGroupRepository)
	svc := NewUserGroupService(mockUserGroupRepo, nil, nil, nil, mockOutbox, nil)

	groupID := "non-existent-group"
	userID := "user-1"

	// Mock: Group does not exist
	mockUserGroupRepo.On("FindByID", mock.Anything, groupID).Return(nil, gorm.ErrRecordNotFound)

	// No Outbox call should happen if group is not found
	mockOutbox.AssertNotCalled(t, "Create")

	err := svc.AddMember(context.Background(), groupID, userID)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "user group not found")

	mockUserGroupRepo.AssertExpectations(t)
}

func TestUserGroupService_RemoveMember_GroupNotFound(t *testing.T) {
	mockOutbox := new(MockKetoOutboxRepositoryShared)
	mockUserGroupRepo := new(MockUserGroupRepository)
	svc := NewUserGroupService(mockUserGroupRepo, nil, nil, nil, mockOutbox, nil)

	groupID := "non-existent-group"
	userID := "user-1"

	// Mock: Group does not exist
	mockUserGroupRepo.On("FindByID", mock.Anything, groupID).Return(nil, gorm.ErrRecordNotFound)

	// No Outbox call should happen if group is not found
	mockOutbox.AssertNotCalled(t, "Create")

	err := svc.RemoveMember(context.Background(), groupID, userID)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "user group not found")

	mockUserGroupRepo.AssertExpectations(t)
}

func TestUserGroupService_AssignRoleToTenant_GroupNotFound(t *testing.T) {
	mockOutbox := new(MockKetoOutboxRepositoryShared)
	mockUserGroupRepo := new(MockUserGroupRepository)
	svc := NewUserGroupService(mockUserGroupRepo, nil, nil, nil, mockOutbox, nil)

	groupID := "non-existent-group"
	tenantID := "tenant-alpha"
	relation := "manage"

	// Mock: Group does not exist
	mockUserGroupRepo.On("FindByID", mock.Anything, groupID).Return(nil, gorm.ErrRecordNotFound)

	// No Outbox call should happen if group is not found
	mockOutbox.AssertNotCalled(t, "Create")

	err := svc.AssignRoleToTenant(context.Background(), groupID, tenantID, relation)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "user group not found")

	mockUserGroupRepo.AssertExpectations(t)
}
