package services

import (
	"context"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
)

func TestNotificationService_ListNotifications(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("Failed to create mock db: %v", err)
	}
	defer db.Close()

	service := NewNotificationService(db, nil)
	ctx := context.Background()
	userID := "019b5290-9680-7c06-9ee3-c9e0e117251b"

	t.Run("returns empty list when no notifications", func(t *testing.T) {
		mock.ExpectQuery("SELECT id, user_id, type, title, message, link, read_at, created_at, updated_at FROM notifications").
			WithArgs(userID).
			WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "type", "title", "message", "link", "read_at", "created_at", "updated_at"}))

		notifications, err := service.ListNotifications(ctx, userID)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if len(notifications) != 0 {
			t.Errorf("Expected 0 notifications, got %d", len(notifications))
		}

		if err := mock.ExpectationsWereMet(); err != nil {
			t.Errorf("Unmet expectations: %v", err)
		}
	})
}

func TestNotificationService_CreateNotification(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("Failed to create mock db: %v", err)
	}
	defer db.Close()

	service := NewNotificationService(db, nil)
	ctx := context.Background()
	userID := "019b5290-9680-7c06-9ee3-c9e0e117251b"

	t.Run("creates a new notification", func(t *testing.T) {
		mock.ExpectExec("INSERT INTO notifications").
			WithArgs(userID, "info", "Test Title", "Test message", nil).
			WillReturnResult(sqlmock.NewResult(1, 1))

		err := service.CreateNotification(ctx, userID, "info", "Test Title", "Test message", nil)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		if err := mock.ExpectationsWereMet(); err != nil {
			t.Errorf("Unmet expectations: %v", err)
		}
	})
}

func TestNotificationService_MarkAsRead(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("Failed to create mock db: %v", err)
	}
	defer db.Close()

	service := NewNotificationService(db, nil)
	ctx := context.Background()
	userID := "019b5290-9680-7c06-9ee3-c9e0e117251b"

	t.Run("marks notification as read", func(t *testing.T) {
		mock.ExpectExec("UPDATE notifications SET read_at").
			WithArgs("1", userID).
			WillReturnResult(sqlmock.NewResult(0, 1))

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

		if err := mock.ExpectationsWereMet(); err != nil {
			t.Errorf("Unmet expectations: %v", err)
		}
	})
}

func TestNotificationService_MarkAllAsRead(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("Failed to create mock db: %v", err)
	}
	defer db.Close()

	service := NewNotificationService(db, nil)
	ctx := context.Background()
	userID := "019b5290-9680-7c06-9ee3-c9e0e117251b"

	t.Run("marks all notifications as read", func(t *testing.T) {
		mock.ExpectExec("UPDATE notifications SET read_at").
			WithArgs(userID).
			WillReturnResult(sqlmock.NewResult(0, 5))

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

		if err := mock.ExpectationsWereMet(); err != nil {
			t.Errorf("Unmet expectations: %v", err)
		}
	})
}

// NewNotificationService instantiation test
func TestNewNotificationService(t *testing.T) {
	service := NewNotificationService(nil, nil)
	if service == nil {
		t.Error("Expected NotificationService to not be nil")
	}
}
