package com.duben.microtribe.utils;

import android.Manifest;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.duben.microtribe.utils.rxutil.CommonUtils;

import androidx.annotation.RequiresApi;

import java.lang.reflect.Method;

/**
 * The type Sim utils.
 */
public class SimUtils {
    private static final String TAG = SimUtils.class.getSimpleName();
    private static final String SIM_STATE = "getSimState";
    private static final String SIM_OPERATOR_NAME = "getNetworkOperatorName";
    private static final String SIM_NETWORK_TYPE = "getNetworkType";
    private static final String SIM_IMEI = "getImei";
    private static final String SIM_LINE_NUMBER = "getLine1Number";
    private static final String SIM_SUBSCRIBER_ID = "getSubscriberId";
//    private static final String SIM_SUBSCRIBER_ID = "getSubscriberId";

    /**
     * Gets sim phonenumber.
     *
     * @param context the context
     * @param slotIdx the slot idx
     * @return the sim phonenumber
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
    public static String getSimPhonenumber(Context context, int slotIdx) {
        if (CommonUtils.INSTANCE.checkPermissionsGranted(context, Manifest.permission.READ_PHONE_STATE) ||
                CommonUtils.INSTANCE.checkPermissionsGranted(context, "android.permission.READ_PRIVILEGED_PHONE_STATE")) {
            Log.d(TAG, "READ_PHONE_STATE permission has BEEN granted to getSimPhonenumber().");
            if (getSimStateBySlotIdx(context, slotIdx)) {
                return (String) getSimByMethod(context, SIM_LINE_NUMBER, getSubidBySlotId(context, slotIdx));
            }
            return null;
        } else {
            Log.d(TAG, "READ_PHONE_STATE permission has NOT been granted to getSimPhonenumber().");
            return null;
        }
    }

    /**
     * Gets sim imei.
     *
     * @param context the context
     * @param slotIdx the slot idx
     * @return the sim imei
     */
    public static String getSimImei(Context context, int slotIdx) {
        if (CommonUtils.INSTANCE.checkPermissionsGranted(context, Manifest.permission.READ_PHONE_STATE) ||
                CommonUtils.INSTANCE.checkPermissionsGranted(context, "android.permission.READ_PRIVILEGED_PHONE_STATE")) {
            Log.d(TAG, "READ_PHONE_STATE permission has BEEN granted to getSimImei().");
            return (String) getSimByMethod(context, SIM_IMEI, slotIdx);
        } else {
            Log.d(TAG, "READ_PHONE_STATE permission has NOT been granted to getSimImei().");
            return null;
        }
    }

    /**
     * Gets sim network type.
     *
     * @param context the context
     * @param slotIdx the slot idx
     * @return the sim network type
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
    public static int getSimNetworkType(Context context, int slotIdx) {
        if (CommonUtils.INSTANCE.checkPermissionsGranted(context, Manifest.permission.READ_PHONE_STATE)) {
            Log.d(TAG, "READ_PHONE_STATE permission has BEEN granted to getSimNetworkType().");
            if (getSimStateBySlotIdx(context, slotIdx)) {
                return (int) getSimByMethod(context, SIM_NETWORK_TYPE, getSubidBySlotId(context, slotIdx));
            }
        } else {
            Log.d(TAG, "READ_PHONE_STATE permission has NOT been granted to getSimNetworkType().");
        }
        return TelephonyManager.NETWORK_TYPE_UNKNOWN;
    }

    /**
     * Gets sim network name.
     *
     * @param context the context
     * @param slotIdx the slot idx
     * @return the sim network name
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
    public static String getSimNetworkName(Context context, int slotIdx) {
        return getNetworkName(getSimNetworkType(context, slotIdx));
    }

    /**
     * Gets sim operator name.
     *
     * @param context the context
     * @param slotIdx the slot idx
     * @return the sim operator name
     */
    public static String getSimOperatorName(Context context, int slotIdx) {
        if (getSimStateBySlotIdx(context, slotIdx)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                return (String) getSimByMethod(context, SIM_OPERATOR_NAME, getSubidBySlotId(context, slotIdx));
            }
        }
        return null;
    }

    /**
     * Gets sim operator name.
     *
     * @param context the context
     * @param slotIdx the slot idx
     * @return the sim operator name
     */
    public static String getSimOperatorName2(Context context, int slotIdx) {
        if (getSimStateBySlotIdx(context, slotIdx)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                return getSimOperatorNameById((String) getSimByMethod(context, SIM_SUBSCRIBER_ID, getSubidBySlotId(context, slotIdx)));
            }
        }
        return null;
    }

    /**
     * Gets sim operator name by single.
     *
     * @param context the context
     * @return the sim operator name
     */
    public static String getSimOperatorNameBySingle(Context context) {
        try {
            TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            return getSimOperatorNameById(telephony.getSimOperator());
        } catch (Exception e) {

        }

        return "unknown";
    }


    private static String getSimOperatorNameById(String IMSI) {
        String operatorName = "unknown";
        if (IMSI != null) {
            if (IMSI.startsWith("46000") || IMSI.startsWith("46002") || IMSI.startsWith("46004") || IMSI.startsWith("46007")) {
                operatorName = "中国移动";
            } else if (IMSI.startsWith("46001") || IMSI.startsWith("46006") || IMSI.startsWith("46009")) {
                operatorName = "中国联通";
            } else if (IMSI.startsWith("46003") || IMSI.startsWith("46005") || IMSI.startsWith("46011")) {
                operatorName = "中国电信";
            }
        }

        return operatorName;
    }

    /**
     * Gets sim state by slot idx.
     *
     * @param context the context
     * @param slotIdx :0(sim1),1(sim2)
     * @return the sim state by slot idx
     */
    public static boolean getSimStateBySlotIdx(Context context, int slotIdx) {
        boolean isReady = false;
        Object getSimState = getSimByMethod(context, SIM_STATE, slotIdx);
        if (getSimState != null) {
            int simState = Integer.parseInt(getSimState.toString());
            if ((simState != TelephonyManager.SIM_STATE_ABSENT) && (simState != TelephonyManager.SIM_STATE_UNKNOWN)) {
                isReady = true;
            }
        }
        return isReady;
    }

    /**
     * Gets sim by method.
     *
     * @param context the context
     * @param method  the method
     * @param param   the param
     * @return the sim by method
     */
    public static Object getSimByMethod(Context context, String method, int param) {
        TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

        try {
            Class<?> telephonyClass = Class.forName(telephony.getClass().getName());
            Class<?>[] parameter = new Class[1];
            parameter[0] = int.class;
            Method getSimState = telephonyClass.getMethod(method, parameter);
            Object[] obParameter = new Object[1];
            obParameter[0] = param;
            Object ob_phone = getSimState.invoke(telephony, obParameter);

            if (ob_phone != null) {
                return ob_phone;
            }
        } catch (Exception e) {
            e.printStackTrace();
            LogUtil.d(e.getMessage());
        }

        return null;
    }

    /**
     * The type Current network.
     */
    public static class CurrentNetwork {
        /**
         * The Which sim.
         */
        public String whichSim;//那张卡
        /**
         * The Net work name.
         */
        public String netWorkName;//几G网络
        /**
         * The Operate name.
         */
        public String operateName;//卡生厂商
    }

    /**
     * Gets current network.
     *
     * @param context the context
     * @return the current network
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    public static CurrentNetwork getCurrentNetwork(Context context) {
        CurrentNetwork currentNetwork = new CurrentNetwork();
        ConnectivityManager connectionManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        assert connectionManager != null;
        NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
        TelephonyManager tm = (TelephonyManager) context
                .getSystemService(Context.TELEPHONY_SERVICE);
        assert tm != null;
        Log.d(TAG, "state:" + tm.getSimState());
        if (networkInfo != null) {
            if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                boolean status = networkInfo.isConnected();
                int sim1NetWorkType = getSimNetworkType(context, 0);
                int sim2NetWorkType = getSimNetworkType(context, 1);
                if (networkInfo.getSubtype() == sim1NetWorkType) {
                    if (getSimStateBySlotIdx(context, 0)) {
                        currentNetwork.netWorkName = getNetworkName(sim1NetWorkType);
                        currentNetwork.operateName = getSimOperatorName(context, 0);
                        currentNetwork.whichSim = "卡1";
                    }
                } else if (networkInfo.getSubtype() == sim2NetWorkType) {
                    if (getSimStateBySlotIdx(context, 1)) {
                        currentNetwork.netWorkName = getNetworkName(sim2NetWorkType);
                        currentNetwork.operateName = getSimOperatorName(context, 1);
                        currentNetwork.whichSim = "卡2";
                    }
                }
            }
        } else {
            // Logger.d(TAG, "network info is null: ");
        }
        return currentNetwork;
    }

    /**
     * Gets network name.
     *
     * @param networkType the network type
     * @return the network name
     */
    public static String getNetworkName(int networkType) {
        switch (networkType) {
            case TelephonyManager.NETWORK_TYPE_GPRS:
            case TelephonyManager.NETWORK_TYPE_EDGE:
            case TelephonyManager.NETWORK_TYPE_CDMA:
            case TelephonyManager.NETWORK_TYPE_1xRTT:
            case TelephonyManager.NETWORK_TYPE_IDEN:
                return "2G";
            case TelephonyManager.NETWORK_TYPE_UMTS:
            case TelephonyManager.NETWORK_TYPE_EVDO_0:
            case TelephonyManager.NETWORK_TYPE_EVDO_A:
            case TelephonyManager.NETWORK_TYPE_HSDPA:
            case TelephonyManager.NETWORK_TYPE_HSUPA:
            case TelephonyManager.NETWORK_TYPE_HSPA:
            case TelephonyManager.NETWORK_TYPE_EVDO_B:
            case TelephonyManager.NETWORK_TYPE_EHRPD:
            case TelephonyManager.NETWORK_TYPE_HSPAP:
                return "3G";
            case TelephonyManager.NETWORK_TYPE_LTE:
                return "4G";
            case TelephonyManager.NETWORK_TYPE_NR:
                return "5G";
            default:
                return "UNKNOWN";
        }
    }

    /**
     * to
     *
     * @param context the context
     * @param slotId  the slot id
     * @return subid by slot id
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
    public static int getSubidBySlotId(Context context, int slotId) {
        SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(
                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        try {
            assert subscriptionManager != null;
            Class<?> telephonyClass = Class.forName(subscriptionManager.getClass().getName());
            Class<?>[] parameter = new Class[1];
            parameter[0] = int.class;
            Method getSimState = telephonyClass.getMethod("getSubId", parameter);
            Object[] obParameter = new Object[1];
            obParameter[0] = slotId;
            Object ob_phone = getSimState.invoke(subscriptionManager, obParameter);

            if (ob_phone != null) {
                Log.d(TAG, "slotId:" + slotId + ";" + ((int[]) ob_phone)[0]);
                return ((int[]) ob_phone)[0];
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;

    }

}
