package org.tzd.frida.windows;

import java.util.ArrayList;
import java.util.List;

/**
 * Frida0 类用于处理 Frida 注入相关的操作和消息传递。
 *
 * <p>此类包括注入 JavaScript 代码到目标进程、消息的发送与接收处理等功能。</p>
 * <p>通过该类，用户可以与 Frida 注入的进程进行交互，并通过回调函数获取日志或错误信息。</p>
 *
 * @author tzdwindows 7
 */
public class Frida0 {

    // 存储回调消息的列表
    static final List<CallbackMessage> CALLBACK_MESSAGE_LIST = new ArrayList<>();

    /**
     * 注入 JavaScript 代码到指定的 Frida 实例，并执行回调任务。
     *
     * <p>该方法调用本地代码注入 JavaScript，并执行传入的回调函数。在 Frida 进程运行期间，回调函数将不断被执行。</p>
     * <p>方法会在 Frida 进程完成后释放资源，并设置 Frida 的运行状态为 `false`。</p>
     *
     * @param jsCode 注入的 JavaScript 代码。
     * @param frida 当前的 Frida 实例，包含进程 PID 等信息。
     * @param callback 运行中的回调任务列表，多个任务可以同时执行。
     */
    static void injection(String jsCode, Frida frida, Runnable... callback) {
        // 调用本地方法进行 JavaScript 注入
        FridaNative.injection(frida.pid, jsCode);

        // 如果有回调任务，循环执行回调
        if (callback != null) {
            while (FridaNative.isRunning()) {
                FridaNative.update();
                for (Runnable runnable : callback) {
                    runnable.run();
                }
            }
        }

        // 释放本地资源
        FridaNative.release();
        frida.isRunning = false;
    }

    /**
     * 发送消息给所有已注册的回调消息对象。
     *
     * <p>此方法会遍历 <code>CALLBACK_MESSAGE_LIST</code> 列表，并触发每个回调对象的 <code>onMessage</code> 方法。</p>
     *
     * @param message 需要发送的消息内容。
     */
    private static void sendMessage(String message) {
        CALLBACK_MESSAGE_LIST.forEach(callbackMessage -> callbackMessage.onMessage(message));
    }

    /**
     * 处理接收到的消息，并根据消息类型做出响应。
     *
     * <p>根据消息中的 `type` 字段，如果是 `error` 类型，抛出运行时异常；如果是 `log` 类型，打印日志。</p>
     * <p>其他类型的消息直接通过回调发送。</p>
     *
     * @param message 接收到的消息内容。
     */
    private static void onMessage(String message) {
        // 获取消息类型
        String type = FridaNative.getStringMember(message, "type");

        // 处理错误类型的消息
        if (!type.isEmpty()) {
            if ("error".equals(type)) {
                sendMessage(FridaNative.getStringMember(message, "payload"));
                throw new RuntimeException(FridaNative.getStringMember(message, "description"));
            } else if ("log".equals(type)) {
                sendMessage(FridaNative.getStringMember(message, "payload"));
            }
            return;
        }

        // 处理普通消息
        sendMessage(message);
    }
}