/* QNotified - An Xposed module for QQ/TIM
 * Copyright (C) 2019-2020 [email protected]
 * https://github.com/cinit/QNotified
 *
 * This software is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <https://www.gnu.org/licenses/>.
 */
package nil.nadph.qnotified.bridge;

import android.content.Context;
import android.os.Parcelable;
import android.widget.Toast;
import com.tencent.mobileqq.app.QQAppInterface;
import nil.nadph.qnotified.util.DexKit;
import nil.nadph.qnotified.util.Utils;

import java.io.Externalizable;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;

import static nil.nadph.qnotified.util.Initiator._SessionInfo;
import static nil.nadph.qnotified.util.Initiator.load;
import static nil.nadph.qnotified.util.Utils.*;

public class ChatActivityFacade {
    public static long[] sendMessage(QQAppInterface qqAppInterface, Context context, Parcelable sessionInfo, String msg,
                                     ArrayList<?> atInfo, Object sendMsgParams) {
        if (qqAppInterface == null) throw new NullPointerException("qqAppInterface == null");
        if (sessionInfo == null) throw new NullPointerException("sessionInfo == null");
        Class facade = DexKit.doFindClass(DexKit.C_FACADE);
        Class SendMsgParams = null;
        Method m = null;
        for (Method mi : facade.getDeclaredMethods()) {
            if (!mi.getReturnType().equals(long[].class)) continue;
            Class[] argt = mi.getParameterTypes();
            if (argt.length != 6) continue;
            if (argt[1].equals(Context.class) && argt[2].equals(_SessionInfo())
                    && argt[3].equals(String.class) && argt[4].equals(ArrayList.class)) {
                m = mi;
                m.setAccessible(true);
                SendMsgParams = argt[5];
                break;
            }
        }
        try {
            return (long[]) m.invoke(null, qqAppInterface, context, sessionInfo, msg, atInfo, sendMsgParams);
        } catch (Exception e) {
            log(e);
            return null;
        }
    }

    public static long[] sendMessage(QQAppInterface qqAppInterface, Context context, Parcelable sessionInfo, String msg) {
        if (qqAppInterface == null) throw new NullPointerException("qqAppInterface == null");
        if (sessionInfo == null) throw new NullPointerException("sessionInfo == null");
        if (msg == null) throw new NullPointerException("msg == null");
        Class facade = DexKit.doFindClass(DexKit.C_FACADE);
        Class SendMsgParams = null;
        Method m = null;
        for (Method mi : facade.getDeclaredMethods()) {
            if (!mi.getReturnType().equals(long[].class)) continue;
            Class[] argt = mi.getParameterTypes();
            if (argt.length != 6) continue;
            if (argt[1].equals(Context.class) && argt[2].equals(_SessionInfo())
                    && argt[3].equals(String.class) && argt[4].equals(ArrayList.class)) {
                m = mi;
                m.setAccessible(true);
                SendMsgParams = argt[5];
                break;
            }
        }
        try {
            return (long[]) m.invoke(null, qqAppInterface, context, sessionInfo, msg, new ArrayList<>(), SendMsgParams.newInstance());
        } catch (Exception e) {
            log(e);
            return null;
        }
    }

    public static long sendPttMessage(QQAppInterface qqAppInterface, Parcelable sessionInfo, String pttPath) {
        if (qqAppInterface == null) throw new NullPointerException("qqAppInterface == null");
        if (sessionInfo == null) throw new NullPointerException("sessionInfo == null");
        if (pttPath == null) throw new NullPointerException("pttPath == null");
        Method send = null;
        for (Method m : DexKit.doFindClass(DexKit.C_FACADE).getMethods()) {
            if (m.getReturnType().equals(long.class)) {
                Class<?>[] clz = m.getParameterTypes();
                if (clz.length != 3) continue;
                if (clz[0].equals(QQAppInterface.class) && clz[1].equals(_SessionInfo()) && clz[2].equals(String.class)) {
                    send = m;
                    break;
                }
            }
        }
        try {
            return (long) send.invoke(null, qqAppInterface, sessionInfo, pttPath);
        } catch (Exception e) {
            log(e);
            return 0;
        }
    }

    public static boolean sendArkAppMessage(QQAppInterface qqAppInterface, Parcelable sessionInfo, Object arkAppMsg) {
        if (qqAppInterface == null) throw new NullPointerException("qqAppInterface == null");
        if (sessionInfo == null) throw new NullPointerException("sessionInfo == null");
        if (arkAppMsg == null) throw new NullPointerException("arkAppMsg == null");
        Method send = null;
        for (Method m : DexKit.doFindClass(DexKit.C_FACADE).getMethods()) {
            if (m.getReturnType().equals(boolean.class)) {
                Class<?>[] clz = m.getParameterTypes();
                if (clz.length != 3) continue;
                if (clz[0].equals(QQAppInterface.class) && clz[1].equals(_SessionInfo()) && clz[2].isInstance(arkAppMsg)) {
                    send = m;
                    break;
                }
            }
        }
        try {
            return (boolean) send.invoke(null, qqAppInterface, sessionInfo, arkAppMsg);
        } catch (Exception e) {
            log(e);
            return false;
        }
    }

    public static void sendAbsStructMsg(QQAppInterface qqAppInterface, Parcelable sessionInfo, Externalizable absStructMsg) {
        if (qqAppInterface == null) throw new NullPointerException("qqAppInterface == null");
        if (sessionInfo == null) throw new NullPointerException("sessionInfo == null");
        if (absStructMsg == null) throw new NullPointerException("absStructMsg == null");
        Method send = null;
        for (Method m : DexKit.doFindClass(DexKit.C_FACADE).getMethods()) {
            if (m.getReturnType().equals(void.class)) {
                Class<?>[] clz = m.getParameterTypes();
                if (clz.length != 3) continue;
                if (clz[0].equals(QQAppInterface.class) && clz[1].equals(_SessionInfo()) && clz[2].isInstance(absStructMsg)) {
                    send = m;
                    break;
                }
            }
        }
        try {
            send.invoke(null, qqAppInterface, sessionInfo, absStructMsg);
        } catch (Exception e) {
            log(e);
        }
    }

    public static void repeatMessage(QQAppInterface app, Parcelable session, Object msg) {
        if (app == null) throw new NullPointerException("app == null");
        if (session == null) throw new NullPointerException("session == null");
        if (msg == null) throw new NullPointerException("msg == null");
        String msgText;
        Class[] argt = null;
        Method m = null;
        switch (getShort$Name(msg)) {
            case "MessageForText":
                msgText = (String) iget_object_or_null(msg, "msg");
                sendMessage(app, getApplication(), session, msgText);
                break;
            case "MessageForPic":
                try {
                    for (Method mi : DexKit.doFindClass(DexKit.C_FACADE).getMethods()) {
                        if (!mi.getName().equals("a") && !mi.getName().equals("b")) continue;
                        argt = mi.getParameterTypes();
                        if (argt.length < 3) continue;
                        if (argt[0].equals(load("com/tencent/mobileqq/app/QQAppInterface")) && argt[1].equals(_SessionInfo())
                                && argt[2].isAssignableFrom(msg.getClass()) && mi.getReturnType().equals(void.class)) {
                            m = mi;
                            break;
                        }
                    }
                    if (argt.length == 3) m.invoke(null, app, session, msg);
                    else m.invoke(null, app, session, msg, 0);
                } catch (Exception e) {
                    Utils.showToast(getApplication(), TOAST_TYPE_ERROR, e.toString().replace("java.lang.", ""), 0);
                    log(e);
                }
                break;
            case "MessageForPtt":
                try {
                    String url = (String) invoke_virtual(msg, "getLocalFilePath");
                    File file = new File(url);
                    if (!file.exists()) {
                        Utils.showToast(getApplication(), TOAST_TYPE_ERROR, "未找到语音文件", Toast.LENGTH_SHORT);
                        return;
                    }
                    sendPttMessage(getQQAppInterface(), session, url);
                } catch (Exception e) {
                    Utils.showToast(getApplication(), TOAST_TYPE_ERROR, e.toString().replace("java.lang.", ""), 0);
                    log(e);
                }
                break;
            default:
                Utils.showToast(getApplication(), TOAST_TYPE_ERROR, "Unsupported msg type: " + getShort$Name(msg), 0);
        }
    }
}