package services

import (
	"context"
	"testing"

	"github.com/google/uuid"
	"go.uber.org/zap"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"veza-backend-api/internal/models"
)

func TestNewEnhancedNotificationService(t *testing.T) {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	if err != nil {
		t.Fatalf("Failed to open database: %v", err)
	}

	// Auto-migrate
	if err := db.AutoMigrate(&models.Notification{}); err != nil {
		t.Fatalf("Failed to migrate: %v", err)
	}

	logger := zap.NewNop()
	service := NewEnhancedNotificationService(db, logger)

	if service == nil {
		t.Error("NewEnhancedNotificationService() returned nil")
	}
	if service.db == nil {
		t.Error("NewEnhancedNotificationService() returned service with nil db")
	}
	if service.logger == nil {
		t.Error("NewEnhancedNotificationService() returned service with nil logger")
	}
}

func TestEnhancedNotificationService_CreateNotification(t *testing.T) {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	if err != nil {
		t.Fatalf("Failed to open database: %v", err)
	}

	if err := db.AutoMigrate(&models.Notification{}); err != nil {
		t.Fatalf("Failed to migrate: %v", err)
	}

	service := NewEnhancedNotificationService(db, zap.NewNop())
	ctx := context.Background()
	userID := uuid.New()

	notification, err := service.CreateNotification(
		ctx,
		userID,
		"test_type",
		"Test Title",
		"Test Content",
		"https://example.com",
	)

	if err != nil {
		t.Fatalf("CreateNotification() error = %v", err)
	}

	if notification == nil {
		t.Error("CreateNotification() returned nil notification")
	}
	if notification.ID == uuid.Nil {
		t.Error("CreateNotification() returned notification with nil ID")
	}
	if notification.UserID != userID {
		t.Errorf("CreateNotification() user_id = %v, want %v", notification.UserID, userID)
	}
	if notification.Type != "test_type" {
		t.Errorf("CreateNotification() type = %v, want test_type", notification.Type)
	}
	if notification.Read != false {
		t.Error("CreateNotification() read should be false")
	}
}

func TestEnhancedNotificationService_GetNotifications(t *testing.T) {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	if err != nil {
		t.Fatalf("Failed to open database: %v", err)
	}

	if err := db.AutoMigrate(&models.Notification{}); err != nil {
		t.Fatalf("Failed to migrate: %v", err)
	}

	service := NewEnhancedNotificationService(db, zap.NewNop())
	ctx := context.Background()
	userID := uuid.New()

	// Create test notifications
	for i := 0; i < 5; i++ {
		_, err := service.CreateNotification(
			ctx,
			userID,
			"test_type",
			"Test Title",
			"Test Content",
			"",
		)
		if err != nil {
			t.Fatalf("Failed to create test notification: %v", err)
		}
	}

	params := NotificationParams{
		UserID:     userID,
		UnreadOnly: false,
		Page:       1,
		Limit:      10,
	}

	result, err := service.GetNotifications(ctx, params)
	if err != nil {
		t.Fatalf("GetNotifications() error = %v", err)
	}

	if result == nil {
		t.Error("GetNotifications() returned nil result")
	}
	if result.Total != 5 {
		t.Errorf("GetNotifications() total = %d, want 5", result.Total)
	}
	if len(result.Notifications) != 5 {
		t.Errorf("GetNotifications() returned %d notifications, want 5", len(result.Notifications))
	}
	if result.UnreadCount != 5 {
		t.Errorf("GetNotifications() unread_count = %d, want 5", result.UnreadCount)
	}
}

func TestEnhancedNotificationService_MarkAsRead(t *testing.T) {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	if err != nil {
		t.Fatalf("Failed to open database: %v", err)
	}

	if err := db.AutoMigrate(&models.Notification{}); err != nil {
		t.Fatalf("Failed to migrate: %v", err)
	}

	service := NewEnhancedNotificationService(db, zap.NewNop())
	ctx := context.Background()
	userID := uuid.New()

	// Create a notification
	notification, err := service.CreateNotification(
		ctx,
		userID,
		"test_type",
		"Test Title",
		"Test Content",
		"",
	)
	if err != nil {
		t.Fatalf("Failed to create notification: %v", err)
	}

	// Mark as read
	err = service.MarkAsRead(ctx, userID, notification.ID)
	if err != nil {
		t.Fatalf("MarkAsRead() error = %v", err)
	}

	// Verify it's marked as read
	readNotification, err := service.GetNotificationByID(ctx, userID, notification.ID)
	if err != nil {
		t.Fatalf("GetNotificationByID() error = %v", err)
	}

	if !readNotification.Read {
		t.Error("MarkAsRead() notification is not marked as read")
	}
	if readNotification.ReadAt == nil {
		t.Error("MarkAsRead() read_at is nil")
	}
}

func TestEnhancedNotificationService_DeleteNotification(t *testing.T) {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	if err != nil {
		t.Fatalf("Failed to open database: %v", err)
	}

	if err := db.AutoMigrate(&models.Notification{}); err != nil {
		t.Fatalf("Failed to migrate: %v", err)
	}

	service := NewEnhancedNotificationService(db, zap.NewNop())
	ctx := context.Background()
	userID := uuid.New()

	// Create a notification
	notification, err := service.CreateNotification(
		ctx,
		userID,
		"test_type",
		"Test Title",
		"Test Content",
		"",
	)
	if err != nil {
		t.Fatalf("Failed to create notification: %v", err)
	}

	// Delete the notification
	err = service.DeleteNotification(ctx, userID, notification.ID)
	if err != nil {
		t.Fatalf("DeleteNotification() error = %v", err)
	}

	// Verify it's deleted
	_, err = service.GetNotificationByID(ctx, userID, notification.ID)
	if err == nil {
		t.Error("DeleteNotification() notification still exists")
	}
}

func TestEnhancedNotificationService_GetUnreadCount(t *testing.T) {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	if err != nil {
		t.Fatalf("Failed to open database: %v", err)
	}

	if err := db.AutoMigrate(&models.Notification{}); err != nil {
		t.Fatalf("Failed to migrate: %v", err)
	}

	service := NewEnhancedNotificationService(db, zap.NewNop())
	ctx := context.Background()
	userID := uuid.New()

	// Create unread notifications
	for i := 0; i < 3; i++ {
		_, err := service.CreateNotification(
			ctx,
			userID,
			"test_type",
			"Test Title",
			"Test Content",
			"",
		)
		if err != nil {
			t.Fatalf("Failed to create notification: %v", err)
		}
	}

	count, err := service.GetUnreadCount(ctx, userID)
	if err != nil {
		t.Fatalf("GetUnreadCount() error = %v", err)
	}

	if count != 3 {
		t.Errorf("GetUnreadCount() = %d, want 3", count)
	}
}

func TestNotificationParams_Defaults(t *testing.T) {
	params := NotificationParams{}

	// Test that defaults are applied in GetNotifications method
	if params.Page < 1 {
		params.Page = 1
	}
	if params.Limit < 1 {
		params.Limit = 20
	}
	if params.Limit > 100 {
		params.Limit = 100
	}

	if params.Page != 1 {
		t.Errorf("Expected default page 1, got %d", params.Page)
	}
	if params.Limit != 20 {
		t.Errorf("Expected default limit 20, got %d", params.Limit)
	}
}

// Note: Full integration tests would require:
// 1. A real database with notifications table
// 2. Test data (notifications with various types, read/unread status)
// 3. Verification of pagination, filtering, and deletion
//
// Example integration test structure:
// func TestEnhancedNotificationService_Integration(t *testing.T) {
//     // Setup test database
//     db := setupTestDB(t)
//     defer cleanupTestDB(t, db)
//
//     // Create test data
//     userID := uuid.New()
//     createTestNotifications(t, db, userID, 25) // 25 notifications
//
//     service := NewEnhancedNotificationService(db, zap.NewNop())
//
//     ctx := context.Background()
//     params := NotificationParams{
//         UserID: userID,
//         Page:   1,
//         Limit:  10,
//     }
//
//     result, err := service.GetNotifications(ctx, params)
//     if err != nil {
//         t.Fatalf("GetNotifications() error = %v", err)
//     }
//
//     if result.Total != 25 {
//         t.Errorf("GetNotifications() total = %d, want 25", result.Total)
//     }
//
//     if len(result.Notifications) != 10 {
//         t.Errorf("GetNotifications() returned %d notifications, want 10", len(result.Notifications))
//     }
// }
