package dev.crucifixbeta.mod.auth;

import java.awt.GraphicsEnvironment;
import java.lang.management.ManagementFactory;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JOptionPane;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;

@Environment(EnvType.CLIENT)
public final class RLGGAntiReverse {
    private static final Set<String> SUSPICIOUS_ARGUMENTS = Set.of(
            "jdwp", "-xdebug", "-xrunjdwp", "frida", "byteman", "jrebel", "hotswap", "dcevm", "bytebuddy");
    private static final Set<String> SUSPICIOUS_PROCESSES = Set.of(
            "recaf", "bytecodeviewer", "bytecode-viewer", "decompiler", "ida.exe", "ida64.exe", "idag.exe",
            "idag64.exe", "idaw.exe", "idaw64.exe", "x32dbg.exe", "x64dbg.exe", "ghidra", "jd-gui",
            "procyon-decompiler", "cfr-decompiler");
    private static final AtomicBoolean CHECKED = new AtomicBoolean();
    private static volatile int decoyState;
    private static volatile boolean bypassNoticeShown;

    private RLGGAntiReverse() {
    }

    private static String findIssue() {
        if (RLGGAuthManager.isReverseLocked()) {
            return RLGGAuthManager.getReverseLockReason();
        }
        if (!hasAuthClassResource(RLGGAuthManager.class)
                || !hasAuthClassResource(RLGGAuthWindow.class)
                || !hasAuthClassResource(RLGGAntiReverse.class)) {
            return "Authorization class resources are missing.";
        }
        String issue = findSuspiciousLaunchArgument();
        if (!issue.isEmpty()) {
            return issue;
        }
        issue = findReverseToolProcess();
        if (!issue.isEmpty()) {
            return issue;
        }
        mixDecoyState();
        return "";
    }

    private static String findSuspiciousLaunchArgument() {
        for (String argument : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
            String normalized = argument.toLowerCase(Locale.ROOT);
            if (normalized.startsWith("-javaagent:")) {
                if (!isAllowedJavaAgent(normalized)) {
                    return "Suspicious javaagent launch argument detected.";
                }
                continue;
            }
            if (normalized.startsWith("-agentlib:") || normalized.startsWith("-agentpath:")) {
                return "Suspicious debug or injection launch argument detected.";
            }
            for (String marker : SUSPICIOUS_ARGUMENTS) {
                if (normalized.contains(marker)) {
                    return "Suspicious reverse-engineering launch argument detected.";
                }
            }
        }
        return "";
    }

    private static String findReverseToolProcess() {
        try (var processes = ProcessHandle.allProcesses()) {
            boolean found = processes.anyMatch(process -> {
                ProcessHandle.Info info = process.info();
                String command = info.command().orElse("").toLowerCase(Locale.ROOT);
                String commandLine = info.commandLine().orElse("").toLowerCase(Locale.ROOT);
                for (String marker : SUSPICIOUS_PROCESSES) {
                    if (command.contains(marker) || commandLine.contains(marker)) {
                        return true;
                    }
                }
                return false;
            });
            return found ? "Reverse-engineering tool process detected." : "";
        } catch (Exception ignored) {
            return "";
        }
    }

    private static boolean isAllowedJavaAgent(String argument) {
        String normalized = argument.toLowerCase(Locale.ROOT);
        return normalized.contains("authlib-injector")
                || normalized.contains("fabric")
                || normalized.contains("minecraft");
    }

    private static boolean hasAuthClassResource(Class<?> type) {
        return type.getResource(type.getSimpleName() + ".class") != null;
    }

    private static void mixDecoyState() {
        List<String> decoys = List.of(
                "ida_graph_auth_success",
                "hexrays_license_branch_0x401000",
                "patch_kmlogon_return_200",
                "fake_card_key_override",
                "bypass_heartbeat_success",
                "crucifix_debug_free_mode",
                "https://127.0.0.1/fake_rlgg_api.php",
                "APPKEY_THIS_IS_A_DECOY_DO_NOT_PATCH",
                "RC4_KEY_DECOY_FOR_IDA_VIEW",
                "jne short loc_verified");
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            for (String decoy : decoys) {
                byte[] value = digest.digest(decoy.getBytes(StandardCharsets.UTF_8));
                decoyState = Integer.rotateLeft(decoyState ^ (value[0] & 0xff), 5) + value[value.length - 1];
            }
        } catch (Exception ignored) {
            decoyState ^= 0x5a17;
        }
    }

    private static void showBlockedMessage(String reason) {
        String message = "Detected reverse-engineering behavior. Access has been blocked.\n\n"
                + reason + "\n\nContact 1920350280 to appeal.";
        System.err.println("CrucifiX authorization blocked: " + reason);
        if (!GraphicsEnvironment.isHeadless()) {
            JOptionPane.showMessageDialog(null, message, "CrucifiX Authorization", JOptionPane.ERROR_MESSAGE);
        }
    }

    private static void showBypassMessage() {
        if (bypassNoticeShown) {
            return;
        }
        bypassNoticeShown = true;
        String message = "\u5df2\u8df3\u8fc7\u62c9\u9ed1";
        System.out.println(message);
        if (!GraphicsEnvironment.isHeadless()) {
            JOptionPane.showMessageDialog(null, message, "CrucifiX Authorization", JOptionPane.INFORMATION_MESSAGE);
        }
    }

    static {
        if (CHECKED.compareAndSet(false, true)) {
            String issue = findIssue();
            if (!issue.isEmpty()) {
                if (RLGGAuthManager.shouldSkipReverseBlacklist()) {
                    showBypassMessage();
                } else {
                    RLGGAuthManager.markReverseDetected(issue);
                    showBlockedMessage(issue);
                }
            }
        }
    }
}
