package repositories

import (
	"testing"
	"time"

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

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
	task := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Fix Roof")

	dueDate := time.Date(2026, 4, 15, 0, 0, 0, 0, time.UTC)
	logEntry, err := repo.LogReminder(task.ID, user.ID, dueDate, models.ReminderStage7Days, nil)
	require.NoError(t, err)
	assert.NotZero(t, logEntry.ID)
	assert.Equal(t, task.ID, logEntry.TaskID)
	assert.Equal(t, user.ID, logEntry.UserID)
	assert.Equal(t, models.ReminderStage7Days, logEntry.ReminderStage)
}

func TestReminderRepository_HasSentReminder(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewReminderRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
	task := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Fix Roof")

	dueDate := time.Date(2026, 4, 15, 12, 30, 0, 0, time.UTC) // Has time component

	// Not sent yet
	sent, err := repo.HasSentReminder(task.ID, user.ID, dueDate, models.ReminderStage7Days)
	require.NoError(t, err)
	assert.False(t, sent)

	// Log it
	_, err = repo.LogReminder(task.ID, user.ID, dueDate, models.ReminderStage7Days, nil)
	require.NoError(t, err)

	// Now should be sent
	sent, err = repo.HasSentReminder(task.ID, user.ID, dueDate, models.ReminderStage7Days)
	require.NoError(t, err)
	assert.True(t, sent)

	// Different stage should not be sent
	sent, err = repo.HasSentReminder(task.ID, user.ID, dueDate, models.ReminderStage3Days)
	require.NoError(t, err)
	assert.False(t, sent)
}

func TestReminderRepository_HasSentReminderBatch(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewReminderRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
	task1 := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Task 1")
	task2 := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Task 2")

	dueDate := time.Date(2026, 4, 15, 0, 0, 0, 0, time.UTC)

	// Log reminder for task1
	_, err := repo.LogReminder(task1.ID, user.ID, dueDate, models.ReminderStage7Days, nil)
	require.NoError(t, err)

	keys := []ReminderKey{
		{TaskID: task1.ID, UserID: user.ID, DueDate: dueDate, Stage: models.ReminderStage7Days},
		{TaskID: task2.ID, UserID: user.ID, DueDate: dueDate, Stage: models.ReminderStage7Days},
	}

	result, err := repo.HasSentReminderBatch(keys)
	require.NoError(t, err)
	assert.True(t, result[0], "task1 reminder should be sent")
	assert.False(t, result[1], "task2 reminder should not be sent")
}

func TestReminderRepository_HasSentReminderBatch_Empty(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewReminderRepository(db)

	result, err := repo.HasSentReminderBatch([]ReminderKey{})
	require.NoError(t, err)
	assert.Empty(t, result)
}

func TestReminderRepository_GetSentRemindersForTask(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewReminderRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
	task := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Fix Roof")

	dueDate := time.Date(2026, 4, 15, 0, 0, 0, 0, time.UTC)
	_, err := repo.LogReminder(task.ID, user.ID, dueDate, models.ReminderStage7Days, nil)
	require.NoError(t, err)
	_, err = repo.LogReminder(task.ID, user.ID, dueDate, models.ReminderStage3Days, nil)
	require.NoError(t, err)

	logs, err := repo.GetSentRemindersForTask(task.ID, user.ID)
	require.NoError(t, err)
	assert.Len(t, logs, 2)
}

func TestReminderRepository_GetSentRemindersForDueDate(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewReminderRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
	task := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Fix Roof")

	dueDate1 := time.Date(2026, 4, 15, 0, 0, 0, 0, time.UTC)
	dueDate2 := time.Date(2026, 5, 15, 0, 0, 0, 0, time.UTC)

	_, err := repo.LogReminder(task.ID, user.ID, dueDate1, models.ReminderStage7Days, nil)
	require.NoError(t, err)
	_, err = repo.LogReminder(task.ID, user.ID, dueDate2, models.ReminderStage7Days, nil)
	require.NoError(t, err)

	logs, err := repo.GetSentRemindersForDueDate(task.ID, user.ID, dueDate1)
	require.NoError(t, err)
	assert.Len(t, logs, 1)
}

func TestReminderRepository_CleanupOldLogs(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewReminderRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
	task := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Fix Roof")

	// Create old log entry (100 days ago)
	oldLog := &models.TaskReminderLog{
		TaskID:        task.ID,
		UserID:        user.ID,
		DueDate:       time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC),
		ReminderStage: models.ReminderStage7Days,
		SentAt:        time.Now().UTC().AddDate(0, 0, -100),
	}
	require.NoError(t, db.Create(oldLog).Error)

	// Create recent log entry
	recentLog := &models.TaskReminderLog{
		TaskID:        task.ID,
		UserID:        user.ID,
		DueDate:       time.Date(2026, 4, 15, 0, 0, 0, 0, time.UTC),
		ReminderStage: models.ReminderStage3Days,
		SentAt:        time.Now().UTC(),
	}
	require.NoError(t, db.Create(recentLog).Error)

	deleted, err := repo.CleanupOldLogs(90)
	require.NoError(t, err)
	assert.Equal(t, int64(1), deleted)

	// Recent log should still exist
	var count int64
	db.Model(&models.TaskReminderLog{}).Count(&count)
	assert.Equal(t, int64(1), count)
}

func TestReminderRepository_GetRecentReminderStats(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewReminderRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
	task := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Fix Roof")

	dueDate := time.Date(2026, 4, 15, 0, 0, 0, 0, time.UTC)
	// Create recent reminders
	_, err := repo.LogReminder(task.ID, user.ID, dueDate, models.ReminderStage7Days, nil)
	require.NoError(t, err)
	_, err = repo.LogReminder(task.ID, user.ID, dueDate, models.ReminderStage3Days, nil)
	require.NoError(t, err)

	stats, err := repo.GetRecentReminderStats(24) // last 24 hours
	require.NoError(t, err)
	assert.Equal(t, int64(1), stats[string(models.ReminderStage7Days)])
	assert.Equal(t, int64(1), stats[string(models.ReminderStage3Days)])
}

func TestReminderRepository_LogReminder_WithNotificationID(t *testing.T) {
	db := testutil.SetupTestDB(t)
	repo := NewReminderRepository(db)

	user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "Password123")
	residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
	task := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Fix Roof")

	// Create a notification
	notif := &models.Notification{
		UserID:           user.ID,
		NotificationType: models.NotificationTaskDueSoon,
		Title:            "Test",
		Body:             "Test body",
	}
	require.NoError(t, db.Create(notif).Error)

	dueDate := time.Date(2026, 4, 15, 0, 0, 0, 0, time.UTC)
	logEntry, err := repo.LogReminder(task.ID, user.ID, dueDate, models.ReminderStage7Days, &notif.ID)
	require.NoError(t, err)
	assert.NotNil(t, logEntry.NotificationID)
	assert.Equal(t, notif.ID, *logEntry.NotificationID)
}
