package services

import (
	"testing"

	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
)

func TestScheduler_NewScheduler(t *testing.T) {
	worker := NewWorker(1)
	defer worker.Shutdown()

	// Use nil database interface for basic testing
	scheduler := NewScheduler(worker, nil)

	assert.NotNil(t, scheduler)
	assert.NotNil(t, scheduler.worker)
	assert.NotNil(t, scheduler.timers)
	assert.NotNil(t, scheduler.scanSettings)
	assert.NotNil(t, scheduler.ctx)
	assert.NotNil(t, scheduler.cancel)
}

func TestScheduler_StartStop(t *testing.T) {
	worker := NewWorker(1)
	scheduler := NewScheduler(worker, nil)

	// Start should not panic
	scheduler.Start()
	assert.NotNil(t, scheduler.ctx)

	// Stop should not panic
	scheduler.Stop()
	worker.Shutdown()
}

func TestScheduler_UpdateScanSettings(t *testing.T) {
	worker := NewWorker(1)
	defer worker.Shutdown()
	scheduler := NewScheduler(worker, nil)

	userID := "test-user-123"

	// Update scan settings
	scheduler.UpdateScanSettings(userID, true, 30)

	scheduler.mu.Lock()
	settings, exists := scheduler.scanSettings[userID]
	scheduler.mu.Unlock()

	assert.True(t, exists)
	assert.Equal(t, userID, settings.UserID)
	assert.True(t, settings.Enabled)
	assert.Equal(t, 30, settings.Frequency)
}

func TestScheduler_UpdateScanSettings_Disabled(t *testing.T) {
	worker := NewWorker(1)
	defer worker.Shutdown()
	scheduler := NewScheduler(worker, nil)

	userID := "test-user-456"

	// Update scan settings to disabled
	scheduler.UpdateScanSettings(userID, false, 60)

	scheduler.mu.Lock()
	settings, exists := scheduler.scanSettings[userID]
	scheduler.mu.Unlock()

	assert.True(t, exists)
	assert.False(t, settings.Enabled)
	assert.Equal(t, 60, settings.Frequency)
}

func TestScheduler_UpdateScanSettings_Overwrite(t *testing.T) {
	worker := NewWorker(1)
	defer worker.Shutdown()
	scheduler := NewScheduler(worker, nil)

	userID := "test-user-789"

	// First update
	scheduler.UpdateScanSettings(userID, true, 30)

	// Overwrite with different settings
	scheduler.UpdateScanSettings(userID, false, 45)

	scheduler.mu.Lock()
	settings, exists := scheduler.scanSettings[userID]
	scheduler.mu.Unlock()

	assert.True(t, exists)
	assert.False(t, settings.Enabled)
	assert.Equal(t, 45, settings.Frequency)
}

func TestScheduler_StopWithActiveTimers(t *testing.T) {
	worker := NewWorker(1)
	scheduler := NewScheduler(worker, nil)

	// Add some fake timers
	scheduler.mu.Lock()
	scheduler.timers["timer1"] = nil
	scheduler.timers["timer2"] = nil
	scheduler.timers["timer3"] = nil
	scheduler.mu.Unlock()

	// Stop should clear timers
	scheduler.Stop()

	scheduler.mu.Lock()
	timerCount := len(scheduler.timers)
	scheduler.mu.Unlock()

	assert.Equal(t, 0, timerCount)

	worker.Shutdown()
}

func TestScheduler_ConcurrentAccess(t *testing.T) {
	worker := NewWorker(1)
	scheduler := NewScheduler(worker, nil)
	scheduler.Start()

	// Concurrent updates should not cause race conditions
	done := make(chan bool, 10)

	for i := 0; i < 10; i++ {
		go func(index int) {
			userID := uuid.New().String()
			scheduler.UpdateScanSettings(userID, true, 30)
			done <- true
		}(i)
	}

	// Wait for all goroutines
	for i := 0; i < 10; i++ {
		<-done
	}

	// Verify all settings were stored
	scheduler.mu.Lock()
	settingCount := len(scheduler.scanSettings)
	scheduler.mu.Unlock()

	assert.Equal(t, 10, settingCount)

	scheduler.Stop()
	worker.Shutdown()
}
