// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.common.util;

import com.hypixel.hytale.function.supplier.SupplierUtil;
import java.util.logging.Level;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.regex.Matcher;
import javax.annotation.Nullable;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.UUID;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import com.hypixel.hytale.logger.HytaleLogger;

public class HardwareUtil
{
    private static final HytaleLogger LOGGER;
    private static final int PROCESS_TIMEOUT_SECONDS = 2;
    private static final Pattern UUID_PATTERN;
    private static final Supplier<UUID> WINDOWS;
    private static final Supplier<UUID> MAC;
    private static final Supplier<UUID> LINUX;
    
    @Nullable
    private static String runCommand(final String... command) {
        try {
            final Process process = new ProcessBuilder(command).start();
            if (process.waitFor(2L, TimeUnit.SECONDS)) {
                return new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8).trim();
            }
            process.destroyForcibly();
        }
        catch (final Exception ex) {}
        return null;
    }
    
    @Nullable
    private static UUID parseUuidFromOutput(final String output) {
        final Matcher matcher = HardwareUtil.UUID_PATTERN.matcher(output);
        if (matcher.find()) {
            return UUID.fromString(matcher.group(1));
        }
        return null;
    }
    
    @Nullable
    private static UUID readMachineIdFile(final Path path) {
        try {
            if (!Files.isReadable(path)) {
                return null;
            }
            final String content = Files.readString(path, StandardCharsets.UTF_8).trim();
            if (content.isEmpty() || content.length() != 32) {
                return null;
            }
            return UUID.fromString(content.substring(0, 8) + "-" + content.substring(8, 12) + "-" + content.substring(12, 16) + "-" + content.substring(16, 20) + "-" + content.substring(20, 32));
        }
        catch (final Exception e) {
            return null;
        }
    }
    
    @Nullable
    public static UUID getUUID() {
        try {
            return switch (SystemUtil.TYPE) {
                default -> throw new MatchException(null, null);
                case WINDOWS -> HardwareUtil.WINDOWS.get();
                case LINUX -> HardwareUtil.LINUX.get();
                case MACOS -> HardwareUtil.MAC.get();
                case OTHER -> throw new RuntimeException("Unknown OS!");
            };
        }
        catch (final Exception e) {
            HardwareUtil.LOGGER.at(Level.WARNING).withCause(e).log("Failed to get Hardware UUID");
            return null;
        }
    }
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
        UUID_PATTERN = Pattern.compile("([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})");
        WINDOWS = SupplierUtil.cache(() -> {
            final String output = runCommand("reg", "query", "HKLM\\SOFTWARE\\Microsoft\\Cryptography", "/v", "MachineGuid");
            if (output != null) {
                for (final String line : output.split("\r?\n")) {
                    if (line.contains("MachineGuid")) {
                        final Matcher matcher = HardwareUtil.UUID_PATTERN.matcher(line);
                        if (matcher.find()) {
                            return UUID.fromString(matcher.group(1));
                        }
                    }
                }
            }
            final String output2 = runCommand("powershell", "-NoProfile", "-Command", "(Get-CimInstance -Class Win32_ComputerSystemProduct).UUID");
            if (output2 != null) {
                final UUID uuid = parseUuidFromOutput(output2);
                if (uuid != null) {
                    return uuid;
                }
            }
            final String output3 = runCommand("wmic", "csproduct", "get", "UUID");
            if (output3 != null) {
                final UUID uuid2 = parseUuidFromOutput(output3);
                if (uuid2 != null) {
                    return uuid2;
                }
            }
            throw new RuntimeException("Failed to get hardware UUID for Windows - registry, PowerShell, and wmic all failed");
        });
        MAC = SupplierUtil.cache(() -> {
            final String output4 = runCommand("/usr/sbin/ioreg", "-rd1", "-c", "IOPlatformExpertDevice");
            if (output4 != null) {
                for (final String line2 : output4.split("\r?\n")) {
                    if (line2.contains("IOPlatformUUID")) {
                        final Matcher matcher2 = HardwareUtil.UUID_PATTERN.matcher(line2);
                        if (matcher2.find()) {
                            return UUID.fromString(matcher2.group(1));
                        }
                    }
                }
            }
            final String output5 = runCommand("/usr/sbin/system_profiler", "SPHardwareDataType");
            if (output5 != null) {
                for (final String line3 : output5.split("\r?\n")) {
                    if (line3.contains("Hardware UUID")) {
                        final Matcher matcher3 = HardwareUtil.UUID_PATTERN.matcher(line3);
                        if (matcher3.find()) {
                            return UUID.fromString(matcher3.group(1));
                        }
                    }
                }
            }
            throw new RuntimeException("Failed to get hardware UUID for macOS - ioreg and system_profiler both failed");
        });
        LINUX = SupplierUtil.cache(() -> {
            final UUID machineId = readMachineIdFile(Path.of("/etc/machine-id", new String[0]));
            if (machineId != null) {
                return machineId;
            }
            else {
                final UUID machineId2 = readMachineIdFile(Path.of("/var/lib/dbus/machine-id", new String[0]));
                if (machineId2 != null) {
                    return machineId2;
                }
                else {
                    try {
                        final Path path = Path.of("/sys/class/dmi/id/product_uuid", new String[0]);
                        if (Files.isReadable(path)) {
                            final String content = Files.readString(path, StandardCharsets.UTF_8).trim();
                            if (!content.isEmpty()) {
                                return UUID.fromString(content);
                            }
                        }
                    }
                    catch (final Exception ex) {}
                    final String output6 = runCommand("dmidecode", "-s", "system-uuid");
                    if (output6 != null) {
                        final UUID uuid3 = parseUuidFromOutput(output6);
                        if (uuid3 != null) {
                            return uuid3;
                        }
                    }
                    throw new RuntimeException("Failed to get hardware UUID for Linux - all methods failed");
                }
            }
        });
    }
}
