package com.xypower.common;

import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.storage.StorageManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;

import com.dev.devapi.api.SysApi;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.util.List;

public class MicroPhotoContext {

    public static final String PACKAGE_NAME_MPAPP = "com.xypower.mpapp";
    public static final String PACKAGE_NAME_MPMASTER = "com.xypower.mpmaster";
    public static final String ACTION_HEARTBEAT_MP = "com.xypower.mpapp.ACT_HB";
    public static final String ACTION_RESTART_MP = "com.xypower.mpapp.ACT_RESTART";
    public static final String ACTION_UPDATE_CONFIGS_MP = "com.xypower.mpapp.ACT_UPD_CFG";

    public final static String DEFAULT_MASTER_SERVER = "61.169.135.150";
    public final static int DEFAULT_MASTER_PORT = 40101;
    public final static String DEFAULT_MASTER_URL = "http://" + DEFAULT_MASTER_SERVER + ":" + Integer.toString(DEFAULT_MASTER_PORT) + "/";
    public final static String MASTER_URL_CMDID = "cmdid";

    public final static int DEFAULT_PROTOCOL = 0xFF00;
    public final static int DEFAULT_HEARTBEAT_TIME_FOR_SEPARATE_NW = 9 * 3600 + 35 * 60; // unit second  9:35
    public final static int DEFAULT_HEARTBEAT_FOR_SHARED_NW = 10;  // minutes
    public final static int DEFAULT_QUICK_HEARTBEAT = 60;  // second

    public static class AppConfig {
        public String cmdid;
        public String server;
        public int port;
        public int protocol;
        public int networkProtocol; //0：tcp  1:udp
        public int network; // 0: SIM1 1: SIM2 2: WIFI
        public int heartbeat;
        public int packetSize;
        public int encryption;  //0：不加密 1：明文  2：加密
        public int channels;  //摄像头通道数目
    }

    public static class MasterConfig {
        public String server;
        public int port;
        public int mntnMode;
        public int quickHbMode;
        public int usingAbsHbTime;
        public int heartbeat;   // Unit minute
        public int quickHeartbeat;   // Unit second
        public int[] absHeartbeats; // second
        public int separateNetwork = 1; // Default is 1
        public int mpappMonitorTimeout = 30 * 60000;    // 30 minutes
        public int timeForKeepingLogs = 15; // Unit day
        public boolean syncTime = false;

        public String getUrl() {
            if (TextUtils.isEmpty(server)) {
                return "";
            }
            return "http://" + server + ":" + Integer.toString(port);
        }
    }

    // 获取主存储卡路径
    public static String getPrimaryStoragePath(Context context) {
        try {
            StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
            Method getVolumePathsMethod = StorageManager.class.getMethod("getVolumePaths", (Class<?>[]) null);
            Object[] args = null;
            String[] paths = (String[]) getVolumePathsMethod.invoke(sm, args);
            // first element in paths[] is primary storage path
            return paths[0];
        } catch (Exception e) {
            // Log.e(TAG, "getPrimaryStoragePath() failed", e);
        }
        return null;
    }

    // 获取次存储卡路径,一般就是外置 TF 卡了. 不过也有可能是 USB OTG 设备...
    // 其实只要判断第二章卡在挂载状态,就可以用了.
    public static String getSecondaryStoragePath(Context context) {
        try {
            StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
            Method getVolumePathsMethod = StorageManager.class.getMethod("getVolumePaths", (Class<?>[]) null);
            Object[] args = null;
            String[] paths = (String[]) getVolumePathsMethod.invoke(sm, args);
            // second element in paths[] is secondary storage path
            return paths.length <= 1 ? null : paths[1];
        } catch (Exception e) {
            // Log.e(TAG, "getSecondaryStoragePath() failed", e);
        }
        return null;
    }

    // 获取存储卡的挂载状态. path 参数传入上两个方法得到的路径
    public String getStorageState(Context context, String path) {
        try {
            StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
            Method getVolumeStateMethod = StorageManager.class.getMethod("getVolumeState", new Class[]{String.class});
            String state = (String) getVolumeStateMethod.invoke(sm, path);
            return state;
        } catch (Exception e) {
            // Log.e(TAG, "getStorageState() failed", e);
        }
        return null;
    }

    public static String formatHeartbeatTime(int ts) {
        int hours = ts / 3600;
        int minutes = (ts / 60) % 60;
        int seconds = ts % 60;

        String str = "";
        if (seconds != 0) {
            str = ((seconds < 10) ? ":0" : ":") + Integer.toString(seconds);
        }

        str = ((minutes < 10) ? ":0" : ":") + Integer.toString(minutes) + str;

        str = ((hours < 10) ? "0" : "") + Integer.toString(hours) + str;

        return str;
    }

    public static boolean isAppAlive(Context context, String packageName) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(Integer.MAX_VALUE);

        boolean isRunning = false;
        for (ActivityManager.RunningServiceInfo rsi : services) {
            if (packageName.equalsIgnoreCase(rsi.service.getPackageName())) {
                isRunning = true;
                break;
            }
        }

        return isRunning;
    }

    public static String buildAppDir(Context contxt) {

        String path = Environment.getExternalStorageDirectory().getAbsolutePath();
        if (!path.endsWith(File.separator)) {
            path += File.separator;
        }
        path += contxt.getPackageName() + File.separator;
        File pathFile = new File(path);
        if (!pathFile.exists() && !pathFile.mkdirs()) {
            return null;
        }

        return path;
    }

    public static void removeMpConfigFiles(Context context) {
        String appPath = buildMpAppDir(context);

        File path = new File(appPath + "data/imgparams/");
        if (path.exists() && path.isDirectory()) {
            FilesUtils.DeleteFilesInPath(path.getAbsolutePath());
        }

        path = new File(appPath + "data/schedules/");
        if (path.exists() && path.isDirectory()) {
            FilesUtils.DeleteFilesInPath(path.getAbsolutePath());
        }

        path = new File(appPath + "data/videoparams/");
        if (path.exists() && path.isDirectory()) {
            FilesUtils.DeleteFilesInPath(path.getAbsolutePath());
        }

        path = new File(appPath + "data/sampling");
        if (path.exists() && path.isFile()) {
            path.delete();
        }
    }

    public static String buildMpAppDir(Context contxt) {

        String path = Environment.getExternalStorageDirectory().getAbsolutePath();
        if (!path.endsWith(File.separator)) {
            path += File.separator;
        }

        path += PACKAGE_NAME_MPAPP + File.separator;
        File pathFile = new File(path);
        if (!pathFile.exists() && !pathFile.mkdirs()) {
            return null;
        }

        return path;
    }

    public static String buildMasterAppDir(Context contxt) {

        String path = Environment.getExternalStorageDirectory().getAbsolutePath();
        if (!path.endsWith(File.separator)) {
            path += File.separator;
        }

        path += PACKAGE_NAME_MPMASTER + File.separator;
        File pathFile = new File(path);
        if (!pathFile.exists() && !pathFile.mkdirs()) {
            return null;
        }

        return path;
    }

    public static boolean hasMpAppConfig(Context context) {
        boolean existed = true;
        String appPath = MicroPhotoContext.buildMpAppDir(context);
        File appPathFile = new File(appPath);
        File appConfigFile = new File(appPathFile, "data/App.json");
        return appConfigFile.exists();
    }

    public static AppConfig getMpAppConfig(Context context) {

        String appPath = buildMpAppDir(context);

        return getMpAppConfig(context, appPath + "data/App.json");
    }

    public static AppConfig getMpAppConfig(Context context, String path) {

        AppConfig appConfig = new AppConfig();

        try {
            String content = FilesUtils.readTextFile(path);

            JSONObject jsonObject = TextUtils.isEmpty(content) ? new JSONObject() : new JSONObject(content);
            appConfig.cmdid = jsonObject.optString(jsonObject.has("cmdid") ? "cmdid" : "CMDID", "");
            appConfig.server = jsonObject.optString(jsonObject.has("server") ? "server" : "Server", "");
            appConfig.port = jsonObject.optInt(jsonObject.has("port") ? "port" : "Port", 0);
            appConfig.protocol = jsonObject.optInt(jsonObject.has("protocol") ? "protocol" : "Protocol", DEFAULT_PROTOCOL);
            appConfig.networkProtocol = jsonObject.optInt(jsonObject.has("networkProtocol") ? "networkProtocol" : "NetworkProtocol", 0);
            appConfig.network = jsonObject.optInt(jsonObject.has("network") ? "network" : "Network", 0);
            appConfig.heartbeat = jsonObject.optInt("heartbeat", 0);
            appConfig.packetSize = jsonObject.optInt("packetSize", 0);
            appConfig.encryption = jsonObject.optInt("encryption", 0);
            appConfig.channels = jsonObject.optInt("channels", 4);

            if (appConfig.protocol == 0) {
                appConfig.protocol = DEFAULT_PROTOCOL;
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return appConfig;
    }

    public static MasterConfig getMasterConfig(Context context) {

        MasterConfig masterConfig = new MasterConfig();
        String appPath = buildMasterAppDir(context);

        try {
            String content = FilesUtils.readTextFile(appPath + "data/Master.json");

            JSONObject jsonObject = TextUtils.isEmpty(content) ? new JSONObject() : new JSONObject(content);
            masterConfig.server = jsonObject.optString("server", "");
            masterConfig.port = jsonObject.optInt("port", 80);
            masterConfig.mntnMode = jsonObject.optInt("mntnMode", 0);
            masterConfig.quickHbMode = jsonObject.optInt("quickHbMode", 0);
            masterConfig.usingAbsHbTime = jsonObject.optInt("usingAbsHbTime", 0);
            masterConfig.separateNetwork = jsonObject.optInt("separateNetwork", 1);
            masterConfig.timeForKeepingLogs = jsonObject.optInt("timeForKeepingLogs", 15);
            masterConfig.syncTime = jsonObject.optInt("syncTime", 0) != 0;

            // masterConfig.mpappMonitorTimeout = jsonObject.optInt("mpappMonitorTimeout", 30 * 60000);
            int mpappMonitorTimeout = jsonObject.optInt("mpappMonitorTimeout", 30 * 60000);
            if (mpappMonitorTimeout >= 4 * 60000 && mpappMonitorTimeout <= 35 * 60000) {
                masterConfig.mpappMonitorTimeout = mpappMonitorTimeout;
            }

            // long defaultHearbeat = masterConfig.separateNetwork == 0 ? DEFAULT_HEARTBEAT_FOR_SHARED_NW : DEFAULT_HEARTBEAT_FOR_SEPARATE_NW;
            masterConfig.heartbeat = jsonObject.optInt("heartbeat", DEFAULT_HEARTBEAT_FOR_SHARED_NW);
            masterConfig.quickHeartbeat = jsonObject.optInt("quickHeartbeat", DEFAULT_QUICK_HEARTBEAT);
            if (jsonObject.has("absHeartbeats")) {
                JSONArray jsonHbs = jsonObject.getJSONArray("absHeartbeats");
                masterConfig.absHeartbeats = new int[jsonHbs.length()];
                for (int idx = 0; idx < jsonHbs.length(); idx++) {
                    masterConfig.absHeartbeats[idx] = jsonHbs.optInt(idx, 0);
                }
            } else {
                masterConfig.absHeartbeats = new int[1];
                masterConfig.absHeartbeats[0] = DEFAULT_HEARTBEAT_TIME_FOR_SEPARATE_NW;
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }

        return masterConfig;
    }

    public static void saveMasterConfig(Context context, MasterConfig masterConfig) {

        String appPath = buildAppDir(context);
        FileOutputStream fos = null;
        OutputStreamWriter outputStreamWriter = null;
        try {

            File dataPath = new File(appPath + "data/");
            if (!dataPath.exists()) {
                dataPath.mkdirs();
            }

            String path = appPath + "data/Master.json";

            String content = FilesUtils.readTextFile(path);

            JSONObject jsonObject = TextUtils.isEmpty(content) ? new JSONObject() : new JSONObject(content);
            jsonObject.put("server", masterConfig.server);
            jsonObject.put("port", masterConfig.port);
            jsonObject.put("mntnMode", masterConfig.mntnMode);
            jsonObject.put("quickHbMode", masterConfig.quickHbMode);
            jsonObject.put("heartbeat", masterConfig.heartbeat);
            jsonObject.put("usingAbsHbTime", masterConfig.usingAbsHbTime);
            jsonObject.put("separateNetwork", masterConfig.separateNetwork);

            JSONArray jsonHbTimes = new JSONArray();
            if (masterConfig.absHeartbeats != null) {
                for (long item : masterConfig.absHeartbeats) {
                    jsonHbTimes.put(jsonHbTimes.length(), item);
                }
            }

            jsonObject.put("absHeartbeats", jsonHbTimes);

            fos = new FileOutputStream(new File(path));
            outputStreamWriter = new OutputStreamWriter(fos, "UTF-8");
            outputStreamWriter.write(jsonObject.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        } finally {
            if (outputStreamWriter != null) {
                try {
                    outputStreamWriter.close();
                } catch (Exception ex) {
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (Exception ex) {
                }
            }
        }
    }

    public static void restartMpApp(Context context, String reason) {
        /*
        Context context = MicroPhotoService.this.getApplicationContext();
        Intent intent = getPackageManager().getLaunchIntentForPackage(context.getPackageName());

        int noDelay = 1;
        intent.putExtra("noDelay", noDelay);
        PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent, 0);
        AlarmManager mgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用
        System.exit(0);

                     */

        restartApp(context, PACKAGE_NAME_MPAPP, reason);
    }

    public static void restartMpApp(Context context, String reason, long delayedTimeMs) {
        Intent intent = context.getPackageManager().getLaunchIntentForPackage(PACKAGE_NAME_MPAPP);

        int noDelay = 1;
        intent.putExtra("noDelay", noDelay);
        if (!TextUtils.isEmpty(reason)) {
            intent.putExtra("reason", reason);
        }
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent restartIntent = PendingIntent.getActivity(context, 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        mgr.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + ((delayedTimeMs > 0) ? delayedTimeMs : 10), restartIntent);
    }

    public static void restartApp(Context context, String packageName, String reason) {
        /*
        Context context = MicroPhotoService.this.getApplicationContext();
        Intent intent = getPackageManager().getLaunchIntentForPackage(context.getPackageName());

        int noDelay = 1;
        intent.putExtra("noDelay", noDelay);
        PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent, 0);
        AlarmManager mgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用
        System.exit(0);

                     */

        try {
            if (TextUtils.equals(packageName, PACKAGE_NAME_MPAPP)) {

                Intent intent = new Intent(ACTION_RESTART_MP);
                intent.putExtra("noDelay", 1);
                if (!TextUtils.isEmpty(reason)) {
                    intent.putExtra("reason", reason);
                }
                intent.setPackage(PACKAGE_NAME_MPAPP);

                context.sendBroadcast(intent);
            } else {
                SysApi.forceStopApp(context, packageName);
            }
            Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
            if (intent != null) {
                intent.putExtra("noDelay", 1);
                if (!TextUtils.isEmpty(reason)) {
                    intent.putExtra("reason", reason);
                }
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                context.startActivity(intent);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void saveMpAppConfig(Context context, AppConfig appConfig) {
        String appPath = buildMpAppDir(context);

        saveMpAppConfig(appPath, appConfig);
    }

    public static void saveMpAppConfig(String path, AppConfig appConfig) {

        FileOutputStream fos = null;
        OutputStreamWriter outputStreamWriter = null;
        try {

            File dataPath = new File(path + "data/");
            if (!dataPath.exists()) {
                dataPath.mkdirs();
            }

            String content = FilesUtils.readTextFile(path + "data/App.json");

            JSONObject jsonObject = TextUtils.isEmpty(content) ? new JSONObject() : new JSONObject(content);
            jsonObject.put("CMDID", appConfig.cmdid);
            jsonObject.put("server", appConfig.server);
            jsonObject.put("port", appConfig.port);
            jsonObject.put("protocol", appConfig.protocol);
            jsonObject.put("networkProtocol", appConfig.networkProtocol);
            jsonObject.put("network", appConfig.network);
            jsonObject.put("encryption", appConfig.encryption);

            if (appConfig.heartbeat > 0) {
                jsonObject.put("heartbeat", appConfig.heartbeat);
            } else {
                jsonObject.remove("heartbeat");
            }
            if (appConfig.packetSize > 0) {
                jsonObject.put("packetSize", appConfig.packetSize);
            } else {
                jsonObject.remove("packetSize");
            }

            fos = new FileOutputStream(new File(path + "data/App.json"));
            outputStreamWriter = new OutputStreamWriter(fos, "UTF-8");
            outputStreamWriter.write(jsonObject.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        } finally {
            if (outputStreamWriter != null) {
                try {
                    outputStreamWriter.close();
                } catch (Exception ex) {
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (Exception ex) {
                }
            }
        }
    }

    public static String getVersionName(Context context) {
        String verName = "";
        try {
            verName = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return verName;
    }

    public static int getVersionCode(Context context) {
        int versionCode = 0;
        try {
            versionCode = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return versionCode;
    }

    public static boolean selectSimCard(final Context context, int num) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
            int activeSubId = SubscriptionManager.getActiveDataSubscriptionId();
            int activeSlotIdx = SubscriptionManager.getSlotIndex(activeSubId);
            if (activeSlotIdx == (num - 1)) {
                // logger.info("Active SimCard is already " + Integer.toString(num));
            } else {
                int subIds[] = subscriptionManager.getSubscriptionIds(num - 1);
                if (subIds != null && subIds.length > 0) {
                    setDefaultDataSubId(context, subIds[0]);
                    // logger.info("Switched To SimCard: " + Integer.toString(num));
                }
            }
        } else {
            SysApi.selectSimCard4Data(context, num);
        }

        return true;
    }

    private static void setDefaultDataSubId(final Context context, int subId) {
        SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        try {

            Method method = subscriptionManager.getClass().getDeclaredMethod("setDefaultDataSubId", int.class);
            try {
                method.invoke(subscriptionManager, subId);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                telephonyManager.setDataEnabled(true);
            }
            Method method1 = telephonyManager.getClass().getDeclaredMethod("setDataEnabled", boolean.class);
            method1.invoke(telephonyManager, true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static int getDefaultDataSubId(final Context context) {
        SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        try {
            Method method = subscriptionManager.getClass().getDeclaredMethod("getDefaultDataSubscriptionId");
            return (int) method.invoke(subscriptionManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

}
