package com.virjar.g4proxy.utils;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;

import com.google.common.collect.Lists;
import com.virjar.g4proxy.bean.App;
import com.virjar.g4proxy.bean.Const;

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

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static android.content.Context.ACTIVITY_SERVICE;
import static android.content.Context.TELEPHONY_SERVICE;
import static com.virjar.g4proxy.Constant.DeviceMessageUtilTAG;


/**
 * Created by liuzhaoce on 2019/4/10.
 */

public class DeviceMessageUtils {

    private static String latitude = "latitude";
    private static String longitude = "longitude";

    //0：UI  1：沙盒
    private static int channel;

    private static LocationListener locationListener = new LocationListener() {

        public void onLocationChanged(Location location) {
            System.out.println("location: " + location);
        }

        @Override
        public void onProviderDisabled(String provider) {

        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }
    };


    public static JSONObject getDeviceMessage(Context context) {

        JSONObject devicesMsg = new JSONObject();
        Map<String, String> latAndLon = DeviceMessageUtils.getLatAndLon(context);

        //对channel完成赋值
        String slaveInfo = getSlaveInfo(context);

        try {
            devicesMsg.put("deviceId", getDeviceId(context));
            devicesMsg.put("brand", android.os.Build.BRAND);
            devicesMsg.put("os", Build.VERSION.RELEASE);
            devicesMsg.put("mac", getNewMac());
            devicesMsg.put("ip", getIPAddress());
            devicesMsg.put("cpuUsage", getCPURateDesc());
            devicesMsg.put("memoryTotal", getMemoryTotal());
            devicesMsg.put("memoryUsage", getMemUsage(context));
            devicesMsg.put("slaveInfo", slaveInfo);
            devicesMsg.put("latitude", Double.valueOf(latAndLon.get(latitude)) == 0.0 ? "": latAndLon.get(latitude));
            devicesMsg.put("longitude", Double.valueOf(latAndLon.get(longitude)) == 0.0 ? "": latAndLon.get(longitude));
            devicesMsg.put("osType", 2);
//            devicesMsg.put("appList", getAPPList(context));
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return devicesMsg;
    }

    /**
     * 获取DeviceId
     */
    private static String getDeviceId(Context context){

        String deviceId;
        //0：UI  1：沙盒
        switch (channel) {
            case 0:
                deviceId = getSerialNumber();
                Log.e(DeviceMessageUtilTAG, "channel: " + channel);
                break;
            case 1:
                deviceId = getSerialNumber() + "_" + getAndroidID(context);
                Log.e(DeviceMessageUtilTAG, "channel: " + channel);
                break;
            default:
                deviceId = null;
                Log.e(DeviceMessageUtilTAG, "channel error!");
        }

        return deviceId;
    }


    /**
     * 获取手机经纬度
     */
    private static Map<String, String> getLatAndLon(Context context) {

        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        Map<String, String> latAndLon = new HashMap<>();
        if (locationManager == null) {
            return latAndLon;
        }
        String bestProvider = locationManager.getBestProvider(getCriteria(), true);
        Log.e(DeviceMessageUtilTAG, "bestProvider: " + bestProvider);

        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return latAndLon;
        }

        locationManager.requestLocationUpdates(bestProvider, 3000, 1, locationListener);

        Location location = locationManager.getLastKnownLocation(bestProvider);
        if (location == null) {
            List<String> providers = locationManager.getProviders(true);

            for (String provider : providers) {

                locationManager.requestLocationUpdates(provider, 3000, 1, locationListener);

                Location l = locationManager.getLastKnownLocation(provider);
                if (l == null) {
                    continue;
                }
                if (location == null || l.getAccuracy() < location.getAccuracy()) {
                    location = l;
                }
            }
        }
        if (location == null) {
            Log.e(DeviceMessageUtilTAG, "location is null");
            latAndLon.put(latitude, "" + String.format(Locale.CHINA, "%.6f", Const.LATITUDE));
            latAndLon.put(longitude, "" + String.format(Locale.CHINA, "%.6f", Const.LONGITUDE));
        }else{
            Log.e(DeviceMessageUtilTAG, "Latitude： " + String.valueOf(location.getLatitude()));
            Log.e(DeviceMessageUtilTAG, "Longitude： " + String.valueOf(location.getLongitude()));
            latAndLon.put(latitude, String.format(Locale.CHINA, "%.6f", location.getLatitude()));
            latAndLon.put(longitude, String.format(Locale.CHINA, "%.6f", location.getLongitude()));
        }
        return latAndLon;
    }

    /**
     * 通过网络接口取mac地址
     */
    private static String getNewMac() {
        try {
            List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

                byte[] macBytes = nif.getHardwareAddress();
                if (macBytes == null) {
                    return null;
                }

                StringBuilder res1 = new StringBuilder();
                for (byte b : macBytes) {
                    res1.append(String.format("%02X:", b));
                }

                if (res1.length() > 0) {
                    res1.deleteCharAt(res1.length() - 1);
                }
                return res1.toString();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }


    /**
     * 通过WiFiManager获取ip地址
     */
    private static String getIPAddress() {
        String ipV6Ip = null;
        String lookUpIP = null;
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                NetworkInterface intf = en.nextElement();
                if (intf.getName() != null && intf.getName().toLowerCase().contains("usbnet")) {
                    continue;
                }
                for (Enumeration<InetAddress> ipAddr = intf.getInetAddresses(); ipAddr.hasMoreElements(); ) {
                    InetAddress inetAddress = ipAddr.nextElement();
                    if (inetAddress.isLoopbackAddress()) {
                        lookUpIP = inetAddress.getHostAddress();
                        continue;
                    }
                    if (inetAddress instanceof Inet4Address) {
                        return inetAddress.getHostAddress();
                    } else {
                        ipV6Ip = inetAddress.getHostAddress();
                    }
                }
            }
        } catch (Exception e) {
            Log.e("TAG", "query local ip failed", e);
        }


        if (lookUpIP != null) {
            return lookUpIP;
        }
        return ipV6Ip;
    }


    /**
     * 获取当前CPU占比
     * 在实际测试中发现，有的手机会隐藏CPU状态，不会完全显示所有CPU信息
     */
    private static String getCPURateDesc() {
        String path = "/proc/stat";// 系统CPU信息文件
        long totalJiffies[] = new long[2];
        long totalIdle[] = new long[2];
        int firstCPUNum = 0;//设置这个参数，这要是防止两次读取文件获知的CPU数量不同，导致不能计算。这里统一以第一次的CPU数量为基准
        FileReader fileReader;
        BufferedReader bufferedReader = null;
        Pattern pattern = Pattern.compile(" [0-9]+");
        for (int i = 0; i < 2; i++) {
            totalJiffies[i] = 0;
            totalIdle[i] = 0;
            try {
                fileReader = new FileReader(path);
                bufferedReader = new BufferedReader(fileReader, 8192);
                int currentCPUNum = 0;
                String str;
                while ((str = bufferedReader.readLine()) != null && (i == 0 || currentCPUNum < firstCPUNum)) {
                    if (str.toLowerCase().startsWith("cpu")) {
                        currentCPUNum++;
                        int index = 0;
                        Matcher matcher = pattern.matcher(str);
                        while (matcher.find()) {
                            try {
                                long tempJiffies = Long.parseLong(matcher.group(0).trim());
                                totalJiffies[i] += tempJiffies;
                                if (index == 3) {//空闲时间为该行第4条栏目
                                    totalIdle[i] += tempJiffies;
                                }
                                index++;
                            } catch (NumberFormatException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    if (i == 0) {
                        firstCPUNum = currentCPUNum;
                        try {//暂停50毫秒，等待系统更新信息。
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (bufferedReader != null) {
                    try {
                        bufferedReader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        double rate;
        if (totalJiffies[0] > 0 && totalJiffies[1] > 0 && totalJiffies[0] != totalJiffies[1]) {
            rate = 1.0 * ((totalJiffies[1] - totalIdle[1]) - (totalJiffies[0] - totalIdle[0])) / (totalJiffies[1] - totalJiffies[0]);
        }else {
            Log.e(DeviceMessageUtilTAG, "get getCPURateDesc failed.");
            return "";
        }

        return String.format(Locale.CHINA, "%.2f", rate * 100);
    }

    /**
     * 获取总内存大小（MB）
     */
    private static String getMemoryTotal() {
        String path = "/proc/meminfo";
        String firstLine = null;
        int totalRam = 0;
        try {
            FileReader fileReader = new FileReader(path);
            BufferedReader br = new BufferedReader(fileReader, 8192);
            firstLine = br.readLine().split("\\s+")[1];
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (firstLine != null) {
            totalRam = (int) Math.ceil((Float.valueOf(Float.valueOf(firstLine) / (1024)).doubleValue()));
        }

        return String.valueOf(totalRam);
    }

    /**
     * 获取SlaveInfo
     */
    private static String getSlaveInfo(Context context) {

        if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            return null;
        }

        String slaveInfoPath = "/sdcard/slave_info.txt";

        Log.e(DeviceMessageUtilTAG, "slave_info.txt path: " + slaveInfoPath);
        String firstLine = null;
        try {
            FileReader fileReader = new FileReader(slaveInfoPath);
            BufferedReader br = new BufferedReader(fileReader, 8192);
            firstLine = br.readLine();
            br.close();
        } catch (Exception e) {
            Log.e(DeviceMessageUtilTAG, "Cannot find slave_info.txt !");
            e.printStackTrace();
        }

        String slaveInfo = null;
        if (firstLine != null) {
            slaveInfo = firstLine.split(",")[0];
            channel = Integer.valueOf(firstLine.split(",")[1]);
        } else {
            Log.e(DeviceMessageUtilTAG, "slave_info.txt can not be parsed!");
        }
        return slaveInfo;
    }


    /**
     * 获取已使用内存大小（MB）
     */
    private static String getMemUsage(Context context) {

        String dir = "/proc/meminfo";
        ActivityManager activityManager = (ActivityManager) context.getApplicationContext().getSystemService(ACTIVITY_SERVICE);

        try {
            FileReader fr = new FileReader(dir);
            BufferedReader br = new BufferedReader(fr, 2048);
            String memoryLine = br.readLine();
            String subMemoryLine = memoryLine.substring(memoryLine.indexOf("MemTotal:"));
            br.close();
            long totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll("\\D+", ""));
            Log.e(DeviceMessageUtilTAG, "totalMemorySize: " + totalMemorySize);
            ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
            if (activityManager == null) {
                return null;
            }
            activityManager.getMemoryInfo(mi);
            long availableSize = mi.availMem / 1024;
            Log.e(DeviceMessageUtilTAG, "availableSize: " + availableSize);
            int memUsage = (int) ((totalMemorySize - availableSize) / 1024);
            return String.valueOf(memUsage);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "null";
    }


    /**
     * 获取手机序列号
     */
    @SuppressLint("HardwareIds")
    static String getSerialNumber() {

        return android.os.Build.SERIAL;
    }

    /**
     * 获取手机android_id
     */
    private static String getAndroidID(Context context) {


        String sandboxIdpath = "/sdcard/qb/android_id.txt";

        String firstLine;
        try {
            FileReader fileReader = new FileReader(sandboxIdpath);
            BufferedReader br = new BufferedReader(fileReader, 8192);
            firstLine = br.readLine();
            br.close();
            if (!TextUtils.isEmpty(firstLine)) {
                return firstLine;
            }
        } catch (Exception e) {
            Log.e(DeviceMessageUtilTAG, "Cannot find android_id.txt !");
            e.printStackTrace();
        }

        return Settings.System.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
    }

    /**
     * 获取app list
     */
    private static List<App> getAPPList(Context context) {
        List<App> appList = Lists.newArrayList();

        PackageManager packageManager = context.getPackageManager();

        Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        List<ResolveInfo> apps = context.getPackageManager().queryIntentActivities(intent, 0);

        for (int i = 0; i < apps.size(); i++) {
            ResolveInfo info = apps.get(i);
            String packageName = info.activityInfo.packageName;
            CharSequence cls = info.activityInfo.name;
            CharSequence name = info.activityInfo.loadLabel(packageManager);
            try {
                PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
                Log.e(DeviceMessageUtilTAG, name + "----" + packageName + "----" + cls + "----versionName: "
                        + packageInfo.versionName + "----versionCode: " + packageInfo.versionCode);
                App app = new App(String.valueOf(name), packageInfo.versionName);
                appList.add(app);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
        return appList;
    }

    /**
     * 获取IMEI
     */
    public static String getMachineImei(Context context) {
        TelephonyManager manager = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
        Class clazz = manager.getClass();
        String imei = "";
        try {
            Method getImei=clazz.getDeclaredMethod("getImei",int.class);//(int slotId)
            getImei.setAccessible(true);
            imei = (String) getImei.invoke(manager);
        } catch (Exception e) {
        }
        return imei;
    }

    /**
     * 获取经纬度provider
     */
    private static Criteria getCriteria() {
        Criteria c = new Criteria();
        c.setAccuracy(Criteria.ACCURACY_COARSE);
        c.setSpeedRequired(false);
        c.setCostAllowed(false);
        c.setBearingRequired(false);
        c.setAltitudeRequired(false);
        c.setPowerRequirement(Criteria.POWER_LOW);
        return c;
    }

    /**
     * IP地址int转String
     */
    private static String intToIp(int i) {

        return (i & 0xFF) + "." +
                ((i >> 8) & 0xFF) + "." +
                ((i >> 16) & 0xFF) + "." +
                (i >> 24 & 0xFF);
    }

}