package org.tzd.frida.windows;

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

/**
 * FridaJsInjector 类负责通过 Frida 向目标进程注入 JavaScript 代码。
 * <p>此类提供了一个方法，允许通过读取指定的 JS 文件，并将其中的代码注入到指定的进程中。</p>
 * <p>如果注入过程中发生错误，类会抛出相应的异常。</p>
 *
 * @author tzdwindows 7
 * @since 1.0
 * @version 1.0
 */
public class FridaJsInjector {

    private Frida frida;

    /**
     * 构造方法，通过传入 PID 和 JavaScript 文件路径来初始化 Frida 实例。
     *
     * @param pid 目标进程的 PID。
     * @param jsFilePath JavaScript 文件的路径。
     */
    public FridaJsInjector(long pid, String jsFilePath) {
        String jsCode = readJsFile(jsFilePath);
        this.frida = new Frida(jsCode, pid);
    }

    /**
     * 读取指定路径的 JavaScript 文件内容。
     *
     * @param jsFilePath JavaScript 文件路径。
     * @return 文件内容的字符串表示。
     */
    private String readJsFile(String jsFilePath) {
        String jsCode = null;
        try {
            jsCode = new String(Files.readAllBytes(Paths.get(jsFilePath)));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("Failed to read the JavaScript file: " + jsFilePath, e);
        }
        return jsCode;
    }

    /**
     * 向目标进程注入 JavaScript 代码。
     * <p>该方法会使用 Frida 将 JavaScript 代码注入到指定的目标进程，并执行相关操作。</p>
     * <p>方法会启动一个线程，并在该线程中执行注入操作。可以通过提供回调函数来接收注入过程中的消息。</p>
     * <p>此方法会检查 Frida 实例是否已经初始化，并在初始化完成后执行 JavaScript 注入。</p>
     *
     * @param callback 传入的回调消息，当接收到来自 Frida 的消息时，该回调会被触发。
     * @param callbackMessage 可选的额外回调函数，用于处理 JavaScript 注入的过程中的操作。
     * @return 返回一个线程对象，用于统一管理和控制线程执行。
     *
     * @throws RuntimeException 如果 Frida 实例未初始化，则抛出运行时异常。
     */
    public Thread injectJs(CallbackMessage callback, Runnable... callbackMessage) {
        if (frida == null) {
            throw new RuntimeException("Frida instance is not initialized.");
        }
        return frida.run(callbackMessage).execute(new FridaRunnable() {
            @Override
            public void run(Frida frida) {
                frida.addCallbackMessage(callback);
            }
        });
    }
}
