package repositories

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/treytartt/honeydue-api/internal/models"
	"github.com/treytartt/honeydue-api/internal/testutil"
)

func TestAdminRepository_Create(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin := &models.AdminUser{
		Email:     "admin@test.com",
		FirstName: "Test",
		LastName:  "Admin",
		Role:      models.AdminRoleAdmin,
		IsActive:  true,
	}
	require.NoError(t, admin.SetPassword("Password123"))

	err := repo.Create(admin)
	require.NoError(t, err)
	assert.NotZero(t, admin.ID)
}

func TestAdminRepository_Create_Duplicate(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin1 := &models.AdminUser{Email: "admin@test.com", Role: models.AdminRoleAdmin}
	require.NoError(t, admin1.SetPassword("Password123"))
	err := repo.Create(admin1)
	require.NoError(t, err)

	admin2 := &models.AdminUser{Email: "admin@test.com", Role: models.AdminRoleAdmin}
	require.NoError(t, admin2.SetPassword("Password123"))
	err = repo.Create(admin2)
	assert.ErrorIs(t, err, ErrAdminExists)
}

func TestAdminRepository_FindByID(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin := &models.AdminUser{Email: "admin@test.com", Role: models.AdminRoleAdmin}
	require.NoError(t, admin.SetPassword("Password123"))
	require.NoError(t, repo.Create(admin))

	found, err := repo.FindByID(admin.ID)
	require.NoError(t, err)
	assert.Equal(t, "admin@test.com", found.Email)
}

func TestAdminRepository_FindByID_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	_, err := repo.FindByID(9999)
	assert.ErrorIs(t, err, ErrAdminNotFound)
}

func TestAdminRepository_FindByEmail(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin := &models.AdminUser{Email: "admin@test.com", Role: models.AdminRoleAdmin}
	require.NoError(t, admin.SetPassword("Password123"))
	require.NoError(t, repo.Create(admin))

	found, err := repo.FindByEmail("admin@test.com")
	require.NoError(t, err)
	assert.Equal(t, admin.ID, found.ID)
}

func TestAdminRepository_FindByEmail_CaseInsensitive(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin := &models.AdminUser{Email: "Admin@Test.com", Role: models.AdminRoleAdmin}
	require.NoError(t, admin.SetPassword("Password123"))
	require.NoError(t, repo.Create(admin))

	found, err := repo.FindByEmail("admin@test.com")
	require.NoError(t, err)
	assert.Equal(t, admin.ID, found.ID)
}

func TestAdminRepository_FindByEmail_NotFound(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	_, err := repo.FindByEmail("nonexistent@test.com")
	assert.ErrorIs(t, err, ErrAdminNotFound)
}

func TestAdminRepository_Update(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin := &models.AdminUser{Email: "admin@test.com", FirstName: "Old", Role: models.AdminRoleAdmin}
	require.NoError(t, admin.SetPassword("Password123"))
	require.NoError(t, repo.Create(admin))

	admin.FirstName = "New"
	err := repo.Update(admin)
	require.NoError(t, err)

	found, err := repo.FindByID(admin.ID)
	require.NoError(t, err)
	assert.Equal(t, "New", found.FirstName)
}

func TestAdminRepository_Delete(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin := &models.AdminUser{Email: "admin@test.com", Role: models.AdminRoleAdmin}
	require.NoError(t, admin.SetPassword("Password123"))
	require.NoError(t, repo.Create(admin))

	err := repo.Delete(admin.ID)
	require.NoError(t, err)

	_, err = repo.FindByID(admin.ID)
	assert.ErrorIs(t, err, ErrAdminNotFound)
}

func TestAdminRepository_UpdateLastLogin(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin := &models.AdminUser{Email: "admin@test.com", Role: models.AdminRoleAdmin}
	require.NoError(t, admin.SetPassword("Password123"))
	require.NoError(t, repo.Create(admin))

	assert.Nil(t, admin.LastLogin)

	err := repo.UpdateLastLogin(admin.ID)
	require.NoError(t, err)

	found, err := repo.FindByID(admin.ID)
	require.NoError(t, err)
	assert.NotNil(t, found.LastLogin)
}

func TestAdminRepository_List(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	for i := 0; i < 5; i++ {
		admin := &models.AdminUser{
			Email: "admin" + string(rune('0'+i)) + "@test.com",
			Role:  models.AdminRoleAdmin,
		}
		require.NoError(t, admin.SetPassword("Password123"))
		require.NoError(t, repo.Create(admin))
	}

	// Page 1
	admins, total, err := repo.List(1, 3)
	require.NoError(t, err)
	assert.Equal(t, int64(5), total)
	assert.Len(t, admins, 3)

	// Page 2
	admins, total, err = repo.List(2, 3)
	require.NoError(t, err)
	assert.Equal(t, int64(5), total)
	assert.Len(t, admins, 2)
}

func TestAdminRepository_ExistsByEmail(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin := &models.AdminUser{Email: "admin@test.com", Role: models.AdminRoleAdmin}
	require.NoError(t, admin.SetPassword("Password123"))
	require.NoError(t, repo.Create(admin))

	exists, err := repo.ExistsByEmail("admin@test.com")
	require.NoError(t, err)
	assert.True(t, exists)

	exists, err = repo.ExistsByEmail("nonexistent@test.com")
	require.NoError(t, err)
	assert.False(t, exists)
}

func TestAdminRepository_ExistsByEmail_CaseInsensitive(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewAdminRepository(db)

	admin := &models.AdminUser{Email: "Admin@Test.com", Role: models.AdminRoleAdmin}
	require.NoError(t, admin.SetPassword("Password123"))
	require.NoError(t, repo.Create(admin))

	exists, err := repo.ExistsByEmail("admin@test.com")
	require.NoError(t, err)
	assert.True(t, exists)
}
