package auth

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/tech/sendico/pkg/merrors"
	"github.com/tech/sendico/pkg/model"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.uber.org/zap"
)

// TestAccountBoundDBImp_Enforce tests the enforce method
func TestAccountBoundDBImp_Enforce(t *testing.T) {
	logger := zap.NewNop()
	db := &AccountBoundDBImp[model.AccountBoundStorable]{
		Logger:        logger,
		PermissionRef: bson.NewObjectID(),
		Collection:    "test_collection",
	}

	t.Run("EnforceMethodExists", func(t *testing.T) {
		// Test that the enforce method exists and can be called
		// This is a basic test to ensure the method signature is correct
		assert.NotNil(t, db.enforce)
	})

	t.Run("PermissionRefSet", func(t *testing.T) {
		// Test that PermissionRef is properly set
		assert.NotEqual(t, bson.NilObjectID, db.PermissionRef)
	})

	t.Run("CollectionSet", func(t *testing.T) {
		// Test that Collection is properly set
		assert.Equal(t, "test_collection", db.Collection)
	})
}

// TestAccountBoundDBImp_InterfaceCompliance tests that the struct implements required interfaces
func TestAccountBoundDBImp_InterfaceCompliance(t *testing.T) {
	logger := zap.NewNop()
	db := &AccountBoundDBImp[model.AccountBoundStorable]{
		Logger:        logger,
		PermissionRef: bson.NewObjectID(),
		Collection:    "test_collection",
	}

	t.Run("StructInitialization", func(t *testing.T) {
		// Test that the struct can be initialized
		assert.NotNil(t, db)
		assert.NotNil(t, db.Logger)
		assert.NotEqual(t, bson.NilObjectID, db.PermissionRef)
		assert.NotEmpty(t, db.Collection)
	})

	t.Run("LoggerInitialization", func(t *testing.T) {
		// Test that logger is properly initialized
		assert.NotNil(t, db.Logger)
	})
}

// TestAccountBoundDBImp_ErrorHandling tests error handling patterns
func TestAccountBoundDBImp_ErrorHandling(t *testing.T) {
	t.Run("AccessDeniedError", func(t *testing.T) {
		// Test that AccessDenied error is properly created
		err := merrors.AccessDenied("test_collection", "read", bson.NilObjectID)
		assert.Error(t, err)
		assert.True(t, errors.Is(err, merrors.ErrAccessDenied))
	})

	t.Run("ErrorTypeChecking", func(t *testing.T) {
		// Test error type checking
		accessDeniedErr := merrors.AccessDenied("test", "read", bson.NilObjectID)
		otherErr := errors.New("other error")

		assert.True(t, errors.Is(accessDeniedErr, merrors.ErrAccessDenied))
		assert.False(t, errors.Is(otherErr, merrors.ErrAccessDenied))
	})
}
