package auctiora;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Test cases for NotificationService.
 * Tests desktop and email notification configuration and delivery.
 */
class NotificationServiceTest {

    @Test
    @DisplayName("Should initialize with desktop-only configuration")
    void testDesktopOnlyConfiguration() {
        NotificationService service = new NotificationService("desktop");
        assertNotNull(service);
    }

    @Test
    @DisplayName("Should initialize with SMTP configuration")
    void testSMTPConfiguration() {
        NotificationService service = new NotificationService(
            "smtp:test@gmail.com:app_password:recipient@example.com"
        );
        assertNotNull(service);
    }

    @Test
    @DisplayName("Should reject invalid SMTP configuration format")
    void testInvalidSMTPConfiguration() {
        // Missing parts
        assertThrows(IllegalArgumentException.class, () ->
            new NotificationService("smtp:incomplete")
        );

        // Wrong format
        assertThrows(IllegalArgumentException.class, () ->
            new NotificationService("smtp:only:two:parts")
        );
    }

    @Test
    @DisplayName("Should reject unknown configuration type")
    void testUnknownConfiguration() {
        assertThrows(IllegalArgumentException.class, () ->
            new NotificationService("unknown_type")
        );
    }

    @Test
    @DisplayName("Should send desktop notification without error")
    void testDesktopNotification() {
        NotificationService service = new NotificationService("desktop");

        // Should not throw exception even if system tray not available
        assertDoesNotThrow(() ->
            service.sendNotification("Test message", "Test title", 0)
        );
    }

    @Test
    @DisplayName("Should send high priority notification")
    void testHighPriorityNotification() {
        NotificationService service = new NotificationService("desktop");

        assertDoesNotThrow(() ->
            service.sendNotification("Urgent message", "High Priority", 1)
        );
    }

    @Test
    @DisplayName("Should send normal priority notification")
    void testNormalPriorityNotification() {
        NotificationService service = new NotificationService("desktop");

        assertDoesNotThrow(() ->
            service.sendNotification("Regular message", "Normal Priority", 0)
        );
    }

    @Test
    @DisplayName("Should handle notification when system tray not supported")
    void testNoSystemTraySupport() {
        NotificationService service = new NotificationService("desktop");

        // Should gracefully handle missing system tray
        assertDoesNotThrow(() ->
            service.sendNotification("Test", "Test", 0)
        );
    }

    @Test
    @DisplayName("Should send email notification with valid SMTP config")
    void testEmailNotificationWithValidConfig() {
        // Note: This won't actually send email without valid credentials
        // But it should initialize properly
        NotificationService service = new NotificationService(
            "smtp:test@gmail.com:fake_password:test@example.com"
        );

        // Should not throw during initialization
        assertNotNull(service);

        // Sending will fail with fake credentials, but shouldn't crash
        assertDoesNotThrow(() ->
            service.sendNotification("Test email", "Email Test", 0)
        );
    }

    @Test
    @DisplayName("Should include both desktop and email when SMTP configured")
    void testBothNotificationChannels() {
        NotificationService service = new NotificationService(
            "smtp:user@gmail.com:password:recipient@example.com"
        );

        // Both desktop and email should be attempted
        assertDoesNotThrow(() ->
            service.sendNotification("Dual channel test", "Test", 0)
        );
    }

    @Test
    @DisplayName("Should handle empty message gracefully")
    void testEmptyMessage() {
        NotificationService service = new NotificationService("desktop");

        assertDoesNotThrow(() ->
            service.sendNotification("", "", 0)
        );
    }

    @Test
    @DisplayName("Should handle very long message")
    void testLongMessage() {
        NotificationService service = new NotificationService("desktop");

        String longMessage = "A".repeat(1000);
        assertDoesNotThrow(() ->
            service.sendNotification(longMessage, "Long Message Test", 0)
        );
    }

    @Test
    @DisplayName("Should handle special characters in message")
    void testSpecialCharactersInMessage() {
        NotificationService service = new NotificationService("desktop");

        assertDoesNotThrow(() ->
            service.sendNotification(
                "€123.45 - Kavel sluit binnen 5 min! ⚠️",
                "Special Chars Test",
                1
            )
        );
    }

    @Test
    @DisplayName("Should accept case-insensitive desktop config")
    void testCaseInsensitiveDesktopConfig() {
        assertDoesNotThrow(() -> {
            new NotificationService("DESKTOP");
            new NotificationService("Desktop");
            new NotificationService("desktop");
        });
    }

    @Test
    @DisplayName("Should validate SMTP config parts count")
    void testSMTPConfigPartsValidation() {
        // Too few parts
        assertThrows(IllegalArgumentException.class, () ->
            new NotificationService("smtp:user:pass")
        );

        // Too many parts should work (extras ignored in split)
        assertDoesNotThrow(() ->
            new NotificationService("smtp:user:pass:email:extra")
        );
    }

    @Test
    @DisplayName("Should handle multiple rapid notifications")
    void testRapidNotifications() {
        NotificationService service = new NotificationService("desktop");

        assertDoesNotThrow(() -> {
            for (int i = 0; i < 5; i++) {
                service.sendNotification("Notification " + i, "Rapid Test", 0);
            }
        });
    }

    @Test
    @DisplayName("Should handle notification with null config parameter")
    void testNullConfigParameter() {
        // Second parameter can be empty string (kept for compatibility)
        assertDoesNotThrow(() ->
            new NotificationService("desktop")
        );
    }

    @Test
    @DisplayName("Should send bid change notification format")
    void testBidChangeNotificationFormat() {
        NotificationService service = new NotificationService("desktop");

        String message = "Nieuw bod op kavel 12345: €150.00 (was €125.00)";
        String title = "Kavel bieding update";

        assertDoesNotThrow(() ->
            service.sendNotification(message, title, 0)
        );
    }

    @Test
    @DisplayName("Should send closing alert notification format")
    void testClosingAlertNotificationFormat() {
        NotificationService service = new NotificationService("desktop");

        String message = "Kavel 12345 sluit binnen 5 min.";
        String title = "Lot nearing closure";

        assertDoesNotThrow(() ->
            service.sendNotification(message, title, 1)
        );
    }

    @Test
    @DisplayName("Should send object detection notification format")
    void testObjectDetectionNotificationFormat() {
        NotificationService service = new NotificationService("desktop");

        String message = "Lot contains: car, truck, machinery\nEstimated value: €5000";
        String title = "Object Detected";

        assertDoesNotThrow(() ->
            service.sendNotification(message, title, 0)
        );
    }
}
