package sql_test

import (
	"context"
	"testing"
	"tercul/internal/data/sql"
	"tercul/internal/domain"
	"tercul/internal/platform/config"
	"tercul/internal/testutil"

	"github.com/stretchr/testify/suite"
)

type UserRepositoryTestSuite struct {
	testutil.IntegrationTestSuite
	UserRepo domain.UserRepository
}

func (s *UserRepositoryTestSuite) SetupSuite() {
	s.IntegrationTestSuite.SetupSuite(testutil.DefaultTestConfig())
	cfg, err := config.LoadConfig()
	s.Require().NoError(err)
	s.UserRepo = sql.NewUserRepository(s.DB, cfg)
}

func (s *UserRepositoryTestSuite) SetupTest() {
	s.IntegrationTestSuite.SetupTest()
	s.DB.Exec("DELETE FROM users")
}

func TestUserRepository(t *testing.T) {
	suite.Run(t, new(UserRepositoryTestSuite))
}

func (s *UserRepositoryTestSuite) createUser(username, email string, role domain.UserRole) *domain.User {
	user := &domain.User{
		Username: username,
		Email:    email,
		Role:     role,
	}
	err := s.UserRepo.Create(context.Background(), user)
	s.Require().NoError(err)
	return user
}

func (s *UserRepositoryTestSuite) TestFindByUsername() {
	s.Run("should find a user by username", func() {
		// Arrange
		expectedUser := s.createUser("testuser", "test@test.com", domain.UserRoleReader)

		// Act
		foundUser, err := s.UserRepo.FindByUsername(context.Background(), "testuser")

		// Assert
		s.Require().NoError(err)
		s.Require().NotNil(foundUser)
		s.Equal(expectedUser.ID, foundUser.ID)
		s.Equal("testuser", foundUser.Username)
	})

	s.Run("should return error if user not found", func() {
		_, err := s.UserRepo.FindByUsername(context.Background(), "nonexistent")
		s.Require().Error(err)
		s.ErrorIs(err, domain.ErrEntityNotFound)
	})
}

func (s *UserRepositoryTestSuite) TestFindByEmail() {
	s.Run("should find a user by email", func() {
		// Arrange
		expectedUser := s.createUser("testuser", "test@test.com", domain.UserRoleReader)

		// Act
		foundUser, err := s.UserRepo.FindByEmail(context.Background(), "test@test.com")

		// Assert
		s.Require().NoError(err)
		s.Require().NotNil(foundUser)
		s.Equal(expectedUser.ID, foundUser.ID)
		s.Equal("test@test.com", foundUser.Email)
	})

	s.Run("should return error if user not found", func() {
		_, err := s.UserRepo.FindByEmail(context.Background(), "nonexistent@test.com")
		s.Require().Error(err)
		s.ErrorIs(err, domain.ErrEntityNotFound)
	})
}

func (s *UserRepositoryTestSuite) TestListByRole() {
	s.Run("should return all users for a given role", func() {
		// Arrange
		s.createUser("reader1", "reader1@test.com", domain.UserRoleReader)
		s.createUser("reader2", "reader2@test.com", domain.UserRoleReader)
		s.createUser("admin1", "admin1@test.com", domain.UserRoleAdmin)

		// Act
		readers, err := s.UserRepo.ListByRole(context.Background(), domain.UserRoleReader)
		s.Require().NoError(err)

		admins, err := s.UserRepo.ListByRole(context.Background(), domain.UserRoleAdmin)
		s.Require().NoError(err)

		// Assert
		s.Len(readers, 2)
		s.Len(admins, 1)
	})

	s.Run("should return empty slice if no users for role", func() {
		users, err := s.UserRepo.ListByRole(context.Background(), domain.UserRoleContributor)
		s.Require().NoError(err)
		s.Len(users, 0)
	})
}