package com.cameleer.server.core.runtime;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

public final class RuntimeDetector {

    private RuntimeDetector() {}

    public record DetectionResult(RuntimeType runtimeType, String mainClass) {}

    /**
     * Detect the runtime type of a file (JAR or native binary).
     * Returns a result with null runtimeType if detection fails.
     */
    public static DetectionResult detect(Path file) {
        if (!Files.exists(file) || Files.isDirectory(file)) {
            return new DetectionResult(null, null);
        }

        // Check if it's a ZIP/JAR (starts with PK magic bytes)
        if (!isZipFile(file)) {
            // Non-ZIP file with content = native binary
            try {
                if (Files.size(file) > 0) {
                    return new DetectionResult(RuntimeType.NATIVE, null);
                }
            } catch (IOException e) {
                // fall through
            }
            return new DetectionResult(null, null);
        }

        // It's a JAR — read the manifest
        try (JarFile jar = new JarFile(file.toFile())) {
            Manifest manifest = jar.getManifest();
            if (manifest == null) {
                return new DetectionResult(null, null);
            }

            String mainClass = manifest.getMainAttributes().getValue("Main-Class");
            if (mainClass == null || mainClass.isBlank()) {
                return new DetectionResult(null, null);
            }

            // Spring Boot: any launcher in org.springframework.boot.loader
            // Derive PropertiesLauncher from the same package as the detected launcher
            // (3.2+ uses org.springframework.boot.loader.launch.*, pre-3.2 uses org.springframework.boot.loader.*)
            if (mainClass.startsWith("org.springframework.boot.loader")) {
                String loaderPackage = mainClass.substring(0, mainClass.lastIndexOf('.'));
                return new DetectionResult(RuntimeType.SPRING_BOOT, loaderPackage + ".PropertiesLauncher");
            }

            // Quarkus
            if (mainClass.equals("io.quarkus.bootstrap.runner.QuarkusEntryPoint")) {
                return new DetectionResult(RuntimeType.QUARKUS, null);
            }

            // Plain Java: has a Main-Class, not a known framework
            return new DetectionResult(RuntimeType.PLAIN_JAVA, mainClass);

        } catch (IOException e) {
            return new DetectionResult(null, null);
        }
    }

    private static boolean isZipFile(Path file) {
        try (InputStream is = Files.newInputStream(file)) {
            byte[] magic = new byte[2];
            int read = is.read(magic);
            return read == 2 && magic[0] == 'P' && magic[1] == 'K';
        } catch (IOException e) {
            return false;
        }
    }
}
