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 TestGetOrCreatePreferences_New_Creates(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewNotificationRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "password")

	// No preferences exist yet for this user
	prefs, err := repo.GetOrCreatePreferences(user.ID)
	require.NoError(t, err)
	require.NotNil(t, prefs)

	// Verify defaults were set
	assert.Equal(t, user.ID, prefs.UserID)
	assert.True(t, prefs.TaskDueSoon)
	assert.True(t, prefs.TaskOverdue)
	assert.True(t, prefs.TaskCompleted)
	assert.True(t, prefs.TaskAssigned)
	assert.True(t, prefs.ResidenceShared)
	assert.True(t, prefs.WarrantyExpiring)
	assert.True(t, prefs.EmailTaskCompleted)

	// Verify it was actually persisted
	var count int64
	db.Model(&models.NotificationPreference{}).Where("user_id = ?", user.ID).Count(&count)
	assert.Equal(t, int64(1), count, "should have exactly one preferences record")
}

func TestGetOrCreatePreferences_AlreadyExists_Returns(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewNotificationRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "password")

	// Create preferences manually first
	existingPrefs := &models.NotificationPreference{
		UserID:             user.ID,
		TaskDueSoon:        true,
		TaskOverdue:        true,
		TaskCompleted:      true,
		TaskAssigned:       true,
		ResidenceShared:    true,
		WarrantyExpiring:   true,
		EmailTaskCompleted: true,
	}
	err := db.Create(existingPrefs).Error
	require.NoError(t, err)
	require.NotZero(t, existingPrefs.ID)

	// GetOrCreatePreferences should return the existing record, not create a new one
	prefs, err := repo.GetOrCreatePreferences(user.ID)
	require.NoError(t, err)
	require.NotNil(t, prefs)

	// The returned record should have the same ID as the existing one
	assert.Equal(t, existingPrefs.ID, prefs.ID, "should return the existing record by ID")
	assert.Equal(t, user.ID, prefs.UserID, "should have correct user_id")

	// Verify still only one record exists (no duplicate created)
	var count int64
	db.Model(&models.NotificationPreference{}).Where("user_id = ?", user.ID).Count(&count)
	assert.Equal(t, int64(1), count, "should still have exactly one preferences record")
}

func TestGetOrCreatePreferences_Idempotent(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewNotificationRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "password")

	// Call twice in succession
	prefs1, err := repo.GetOrCreatePreferences(user.ID)
	require.NoError(t, err)

	prefs2, err := repo.GetOrCreatePreferences(user.ID)
	require.NoError(t, err)

	// Both should return the same record
	assert.Equal(t, prefs1.ID, prefs2.ID)

	// Should only have one record
	var count int64
	db.Model(&models.NotificationPreference{}).Where("user_id = ?", user.ID).Count(&count)
	assert.Equal(t, int64(1), count, "should have exactly one preferences record after two calls")
}
