package com.cameleer.server.core.runtime;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

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

class RuntimeDetectorTest {

    @TempDir
    Path tempDir;

    private Path createJarWithMainClass(String mainClass) throws IOException {
        Path jar = tempDir.resolve("app.jar");
        Manifest manifest = new Manifest();
        manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
        manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, mainClass);
        try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(jar.toFile()), manifest)) {
            // empty JAR with manifest
        }
        return jar;
    }

    private Path createJarWithoutMainClass() throws IOException {
        Path jar = tempDir.resolve("no-main.jar");
        Manifest manifest = new Manifest();
        manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
        try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(jar.toFile()), manifest)) {
            // empty JAR, no Main-Class
        }
        return jar;
    }

    @Test
    void detectsSpringBootJarLauncher() throws IOException {
        Path jar = createJarWithMainClass("org.springframework.boot.loader.launch.JarLauncher");
        RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar);
        assertEquals(RuntimeType.SPRING_BOOT, result.runtimeType());
        assertEquals("org.springframework.boot.loader.launch.PropertiesLauncher", result.mainClass());
    }

    @Test
    void detectsSpringBootPropertiesLauncher() throws IOException {
        Path jar = createJarWithMainClass("org.springframework.boot.loader.launch.PropertiesLauncher");
        RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar);
        assertEquals(RuntimeType.SPRING_BOOT, result.runtimeType());
        assertEquals("org.springframework.boot.loader.launch.PropertiesLauncher", result.mainClass());
    }

    @Test
    void detectsSpringBootLegacyLauncher() throws IOException {
        Path jar = createJarWithMainClass("org.springframework.boot.loader.JarLauncher");
        RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar);
        assertEquals(RuntimeType.SPRING_BOOT, result.runtimeType());
        assertEquals("org.springframework.boot.loader.PropertiesLauncher", result.mainClass());
    }

    @Test
    void detectsQuarkus() throws IOException {
        Path jar = createJarWithMainClass("io.quarkus.bootstrap.runner.QuarkusEntryPoint");
        RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar);
        assertEquals(RuntimeType.QUARKUS, result.runtimeType());
        assertNull(result.mainClass());
    }

    @Test
    void detectsPlainJava() throws IOException {
        Path jar = createJarWithMainClass("com.example.MyApp");
        RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar);
        assertEquals(RuntimeType.PLAIN_JAVA, result.runtimeType());
        assertEquals("com.example.MyApp", result.mainClass());
    }

    @Test
    void detectsNativeBinary() throws IOException {
        Path binary = tempDir.resolve("app");
        // ELF header (not a ZIP/JAR)
        Files.write(binary, new byte[]{0x7f, 'E', 'L', 'F', 0, 0, 0, 0});
        RuntimeDetector.DetectionResult result = RuntimeDetector.detect(binary);
        assertEquals(RuntimeType.NATIVE, result.runtimeType());
        assertNull(result.mainClass());
    }

    @Test
    void returnsNullForJarWithoutMainClass() throws IOException {
        Path jar = createJarWithoutMainClass();
        RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar);
        assertNull(result.runtimeType());
        assertNull(result.mainClass());
    }

    @Test
    void returnsNullForEmptyFile() throws IOException {
        Path empty = tempDir.resolve("empty");
        Files.write(empty, new byte[0]);
        RuntimeDetector.DetectionResult result = RuntimeDetector.detect(empty);
        assertNull(result.runtimeType());
        assertNull(result.mainClass());
    }
}
