package com.miraclegarden.smsmessage.xposed.hook;

import android.app.Notification;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;

import com.miraclegarden.smsmessage.xposed.HookForwarder;

import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Map;

import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;

/**
 * 银行 App Hook 公共工具：RemoteMessage / Notification 解析与去重转发。
 */
public final class BankHookHelper {

    private static final String TAG = "notiMessageHook/Bank";
    private static final int DEDUP_SIZE = 256;

    private static final ArrayDeque<String> RECENT_KEYS = new ArrayDeque<>();
    private static final HashSet<String> RECENT_SET = new HashSet<>();

    private BankHookHelper() {
    }

    public static void hookFcmService(de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam lpparam,
                                      String serviceClass, String source) {
        try {
            de.robv.android.xposed.XposedHelpers.findAndHookMethod(
                    serviceClass,
                    lpparam.classLoader,
                    "onMessageReceived",
                    "com.google.firebase.messaging.RemoteMessage",
                    new de.robv.android.xposed.XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) {
                            if (param.args == null || param.args.length == 0 || param.args[0] == null) {
                                return;
                            }
                            Context context = getContext();
                            if (context == null) {
                                return;
                            }
                            CharSequence[] parts = extractRemoteMessage(param.args[0]);
                            forward(context, lpparam.packageName, parts[0], parts[1], source);
                        }
                    }
            );
            XposedBridge.log(TAG + " FCM hook installed: " + serviceClass + " (" + lpparam.packageName + ")");
        } catch (Throwable t) {
            XposedBridge.log(TAG + " FCM hook failed " + serviceClass + ": " + t.getMessage());
        }
    }

    public static void forwardFromNotification(Context context, String packageName,
                                               Notification notification, String source) {
        if (notification == null) {
            return;
        }
        CharSequence[] parts = extractNotification(notification);
        forward(context, packageName, parts[0], parts[1], source);
    }

    private static void forward(Context context, String packageName,
                                CharSequence title, CharSequence content, String source) {
        String titleStr = title != null ? title.toString().trim() : "";
        String contentStr = content != null ? content.toString().trim() : "";
        if (TextUtils.isEmpty(titleStr) && TextUtils.isEmpty(contentStr)) {
            return;
        }
        if (TextUtils.isEmpty(titleStr)) {
            titleStr = packageName;
        }
        if (TextUtils.isEmpty(contentStr)) {
            contentStr = titleStr;
        }
        String dedupKey = packageName + "|" + titleStr + "|" + contentStr;
        if (!remember(dedupKey)) {
            return;
        }
        XposedBridge.log(TAG + " forward [" + source + "] " + titleStr + " / " + contentStr);
        HookForwarder.forward(context, packageName, titleStr, contentStr, source);
    }

    static CharSequence[] extractRemoteMessage(Object remoteMessage) {
        String title = "";
        String body = "";
        try {
            Object notification = XposedHelpers.callMethod(remoteMessage, "getNotification");
            if (notification != null) {
                Object t = XposedHelpers.callMethod(notification, "getTitle");
                Object b = XposedHelpers.callMethod(notification, "getBody");
                if (t != null) {
                    title = String.valueOf(t).trim();
                }
                if (b != null) {
                    body = String.valueOf(b).trim();
                }
            }
        } catch (Throwable ignored) {
        }

        if (TextUtils.isEmpty(body)) {
            body = stringifyDataMap(remoteMessage);
        }
        return new CharSequence[]{title, body};
    }

    private static String stringifyDataMap(Object remoteMessage) {
        try {
            Object dataObj = XposedHelpers.callMethod(remoteMessage, "getData");
            if (!(dataObj instanceof Map)) {
                return "";
            }
            Map<?, ?> data = (Map<?, ?>) dataObj;
            if (data.isEmpty()) {
                return "";
            }
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<?, ?> entry : data.entrySet()) {
                if (entry.getKey() == null) {
                    continue;
                }
                if (sb.length() > 0) {
                    sb.append('\n');
                }
                sb.append(entry.getKey()).append('=');
                if (entry.getValue() != null) {
                    sb.append(entry.getValue());
                }
            }
            return sb.toString().trim();
        } catch (Throwable ignored) {
            return "";
        }
    }

    static CharSequence[] extractNotification(Notification notification) {
        Bundle extras = notification.extras;
        if (extras == null) {
            return new CharSequence[]{"", ""};
        }
        CharSequence title = firstNonEmpty(
                extras.getCharSequence(Notification.EXTRA_TITLE),
                extras.getCharSequence(Notification.EXTRA_TITLE_BIG),
                extras.getString(Notification.EXTRA_TITLE)
        );
        CharSequence text = firstNonEmpty(
                extras.getCharSequence(Notification.EXTRA_TEXT),
                extras.getCharSequence(Notification.EXTRA_BIG_TEXT),
                extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT),
                extras.getString(Notification.EXTRA_TEXT)
        );
        if (TextUtils.isEmpty(text)) {
            text = extras.getString("gcm.n.body");
        }
        if (TextUtils.isEmpty(title)) {
            title = extras.getString("gcm.n.title");
        }
        return new CharSequence[]{title, text};
    }

    private static CharSequence firstNonEmpty(CharSequence... values) {
        for (CharSequence value : values) {
            if (!TextUtils.isEmpty(value)) {
                return value;
            }
        }
        return "";
    }

    private static synchronized boolean remember(String key) {
        if (RECENT_SET.contains(key)) {
            return false;
        }
        RECENT_SET.add(key);
        RECENT_KEYS.addLast(key);
        while (RECENT_KEYS.size() > DEDUP_SIZE) {
            String oldest = RECENT_KEYS.removeFirst();
            RECENT_SET.remove(oldest);
        }
        return true;
    }

    static Context getContext() {
        try {
            Class<?> activityThread = XposedHelpers.findClass("android.app.ActivityThread", null);
            Object app = XposedHelpers.callStaticMethod(activityThread, "currentApplication");
            if (app instanceof Context) {
                return (Context) app;
            }
        } catch (Throwable ignored) {
        }
        return null;
    }
}
