package auctiora;

import org.junit.jupiter.api.*;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

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

/**
 * Test cases for ObjectDetectionService.
 * Tests YOLO model loading and object detection functionality.
 */
class ObjectDetectionServiceTest {

    private static final String TEST_CFG = "test_yolo.cfg";
    private static final String TEST_WEIGHTS = "test_yolo.weights";
    private static final String TEST_CLASSES = "test_classes.txt";

    @Test
    @DisplayName("Should initialize with missing YOLO models (disabled mode)")
    void testInitializeWithoutModels() throws IOException {
        // When models don't exist, service should initialize in disabled mode
        ObjectDetectionService service = new ObjectDetectionService(
            "non_existent.cfg",
            "non_existent.weights",
            "non_existent.txt"
        );

        assertNotNull(service);
    }

    @Test
    @DisplayName("Should return empty list when detection is disabled")
    void testDetectObjectsWhenDisabled() throws IOException {
        ObjectDetectionService service = new ObjectDetectionService(
            "non_existent.cfg",
            "non_existent.weights",
            "non_existent.txt"
        );

        var result = service.detectObjects("any_image.jpg");

        assertNotNull(result);
        assertTrue(result.isEmpty());
    }

    @Test
    @DisplayName("Should handle invalid image path gracefully")
    void testInvalidImagePath() throws IOException {
        ObjectDetectionService service = new ObjectDetectionService(
            "non_existent.cfg",
            "non_existent.weights",
            "non_existent.txt"
        );

        var result = service.detectObjects("completely_invalid_path.jpg");

        assertNotNull(result);
        assertTrue(result.isEmpty());
    }

    @Test
    @DisplayName("Should handle empty image file")
    void testEmptyImageFile() throws IOException {
        ObjectDetectionService service = new ObjectDetectionService(
            "non_existent.cfg",
            "non_existent.weights",
            "non_existent.txt"
        );

        // Create empty test file
        var tempFile = Files.createTempFile("test_image", ".jpg");
        try {
            var result = service.detectObjects(tempFile.toString());
            assertNotNull(result);
            assertTrue(result.isEmpty());
        } finally {
            Files.deleteIfExists(tempFile);
        }
    }

    @Test
    @DisplayName("Should initialize successfully with valid model files")
    void testInitializeWithValidModels() throws IOException {
        // Create dummy model files for testing initialization
        var cfgPath = Paths.get(TEST_CFG);
        var weightsPath = Paths.get(TEST_WEIGHTS);
        var classesPath = Paths.get(TEST_CLASSES);

        try {
            Files.writeString(cfgPath, "[net]\nwidth=416\nheight=416\n");
            Files.write(weightsPath, new byte[]{0, 1, 2, 3});
            Files.writeString(classesPath, "person\ncar\ntruck\n");

            // Note: This will still fail to load actual YOLO model without OpenCV
            // But it tests file existence check
            assertDoesNotThrow(() -> {
                try {
                    new ObjectDetectionService(TEST_CFG, TEST_WEIGHTS, TEST_CLASSES);
                } catch (IOException e) {
                    // Expected if OpenCV not loaded
                    assertTrue(e.getMessage().contains("Failed to initialize"));
                }
            });
        } finally {
            Files.deleteIfExists(cfgPath);
            Files.deleteIfExists(weightsPath);
            Files.deleteIfExists(classesPath);
        }
    }

    @Test
    @DisplayName("Should handle missing class names file")
    void testMissingClassNamesFile() {
        assertThrows(IOException.class, () -> {
            new ObjectDetectionService("non_existent.cfg", "non_existent.weights", "non_existent.txt");
        });
    }

    @Test
    @DisplayName("Should detect when model files are missing")
    void testDetectMissingModelFiles() throws IOException {
        // Should initialize in disabled mode
        ObjectDetectionService service = new ObjectDetectionService(
            "missing.cfg",
            "missing.weights",
            "missing.names"
        );

        // Should return empty results when disabled
        var results = service.detectObjects("test.jpg");
        assertTrue(results.isEmpty());
    }

    @Test
    @DisplayName("Should return unique labels only")
    void testUniqueLabels() throws IOException {
        // When disabled, returns empty list (unique by default)
        ObjectDetectionService service = new ObjectDetectionService(
            "non_existent.cfg",
            "non_existent.weights",
            "non_existent.txt"
        );

        var result = service.detectObjects("test.jpg");
        assertNotNull(result);
        assertEquals(0, result.size());
    }

    @Test
    @DisplayName("Should handle multiple detections in same image")
    void testMultipleDetections() throws IOException {
        // Test structure for when detection works
        // With actual YOLO models, this would return multiple objects
        ObjectDetectionService service = new ObjectDetectionService(
            "non_existent.cfg",
            "non_existent.weights",
            "non_existent.txt"
        );

        var result = service.detectObjects("test_image.jpg");
        assertNotNull(result);
        // When disabled, returns empty list
        assertTrue(result.isEmpty());
    }

    @Test
    @DisplayName("Should respect confidence threshold")
    void testConfidenceThreshold() throws IOException {
        // The service uses 0.5 confidence threshold
        // This test documents that behavior
        ObjectDetectionService service = new ObjectDetectionService(
            "non_existent.cfg",
            "non_existent.weights",
            "non_existent.txt"
        );

        // Low confidence detections should be filtered out
        // (when detection is working)
        var result = service.detectObjects("test.jpg");
        assertNotNull(result);
    }
}
