package com.example.modifier.utils;

import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneNumberUtils;
import android.telephony.SmsManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.google.gson.Gson;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class RcsHackTool {
    private static final String TAG = "RcsHackTool";

    // 获取对应的Intent数据
    public static Intent createSmsIntent(String number, String body, int slot, int subId) {
        SmsManager smsManager = SmsManager.getDefault();
        // 防止短信过长
        ArrayList<String> messages = smsManager.divideMessage(body);
        int size = messages.size();
        byte[][] objArray = new byte[size][];
        for (int i = 0; i < size; ++i) {
            byte[] pduu = createFakeSms(number, messages.get(i));
            objArray[i] = pduu;
        }
        Intent intent = new Intent();
        intent.setAction("android.provider.Telephony.SMS_DELIVER");

        intent.putExtra("android.telephony.extra.SUBSCRIPTION_INDEX", subId);
        intent.putExtra("messageId", Long.valueOf((int) Math.floor(Math.random() * 100000000)).longValue());
        intent.putExtra("pdus", objArray);
        intent.putExtra("format", "3gpp");
        intent.putExtra("android.telephony.extra.SLOT_INDEX", slot);
        intent.putExtra("phone", slot);
        intent.putExtra("subscription", subId);
        return intent;
    }

    public static Intent createSmsIntent(Context context, String number, String body) {
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
        final int simCount = subscriptionManager.getActiveSubscriptionInfoCountMax();
        int subId = 0;
        int slot = 0;
        for (int i = 0; i < simCount; i++) {
            SubscriptionInfo subInfo = subscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(i);
            if (subInfo != null) {
                Log.d(TAG, "subId: " + subInfo.getSubscriptionId());
                subId = subInfo.getSubscriptionId();
                slot = subInfo.getSimSlotIndex();
                break;
            }
        }

        return createSmsIntent(number, body, slot, subId);
    }

    // 创建pdu
    public static byte[] createFakeSms(String sender, String body) {
        byte[] pdu = null;
        byte[] scBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD("0000000000");
        byte[] senderBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(sender);
        int lsmcs = scBytes.length;
        // 时间处理，包括年月日时分秒以及时区和夏令时
        byte[] dateBytes = new byte[7];
        Calendar calendar = new GregorianCalendar();
        dateBytes[0] = reverseByte((byte) (calendar.get(Calendar.YEAR)));
        dateBytes[1] = reverseByte((byte) (calendar.get(Calendar.MONTH) + 1));
        dateBytes[2] = reverseByte((byte) (calendar.get(Calendar.DAY_OF_MONTH)));
        dateBytes[3] = reverseByte((byte) (calendar.get(Calendar.HOUR_OF_DAY)));
        dateBytes[4] = reverseByte((byte) (calendar.get(Calendar.MINUTE)));
        dateBytes[5] = reverseByte((byte) (calendar.get(Calendar.SECOND)));
        dateBytes[6] = reverseByte((byte) ((calendar.get(Calendar.ZONE_OFFSET)
                + calendar.get(Calendar.DST_OFFSET)) / (60 * 1000 * 15)));
        try {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            bo.write(lsmcs);// 短信服务中心长度
            bo.write(scBytes);// 短信服务中心号码
            bo.write(0x04);
            bo.write((byte) sender.length());// 发送方号码长度
            bo.write(senderBytes);// 发送方号码
            bo.write(0x00);// 协议标示，00为普通GSM，点对点方式
            try {
                String className = "com.android.internal.telephony.GsmAlphabet";
                Class<?> clazz = Class.forName(className);
                Method method = clazz.getMethod("stringToGsm7BitPacked", new Class[]{String.class});
                method.setAccessible(true);
                byte[] bodybytes = (byte[]) method.invoke(null, body);

                bo.write(0x00); // encoding: 0 for default 7bit
                bo.write(dateBytes);
                bo.write(bodybytes);
            } catch (Exception e) {
                // 下面是UCS-2编码的处理，中文短信就需要用此种方式
                byte[] bodyBytes = encodeUCS2(body, null);
                bo.write(0x08); // encoding: 8 for UCS-2
                bo.write(dateBytes);
                bo.write(bodyBytes);// 其中encodeUCS2是从系统中复制过来的，并不是我写的
                // 源码具体位置在
                // frameworks/base/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
            }

            pdu = bo.toByteArray();
        } catch (IOException e) {
        }
        return pdu;
    }

    private static byte reverseByte(byte b) {
        return (byte) ((b & 0xF0) >> 4 | (b & 0x0F) << 4);
    }

    private static byte[] encodeUCS2(String message, byte[] header) throws UnsupportedEncodingException {
        byte[] userData, textPart;
        textPart = message.getBytes(StandardCharsets.UTF_16BE);

        if (header != null) {
            // Need 1 byte for UDHL
            userData = new byte[header.length + textPart.length + 1];

            userData[0] = (byte) header.length;
            System.arraycopy(header, 0, userData, 1, header.length);
            System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length);
        } else {
            userData = textPart;
        }
        byte[] ret = new byte[userData.length + 1];
        ret[0] = (byte) (userData.length & 0xff);
        System.arraycopy(userData, 0, ret, 1, userData.length);
        return ret;
    }

    public static String toGson(Object obj) {
        Gson gson = new Gson();
        return gson.toJson(obj);
    }
}