package tech.starwin.utils.collection;

import android.Manifest;
import android.content.Context;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Base64;

import com.annimon.stream.Stream;
import com.annimon.stream.function.BiFunction;

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

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import tech.starwin.LibConfig;

import com.common.Collector;

import tech.starwin.database.DataBaseHelper;

import com.common.bean.CollectInfoEntity;
import com.common.bean.IncomeMessageProto;

import tech.starwin.network.Gateway;
import tech.starwin.utils.LogUtils;
import tech.starwin.utils.LoginManager;
import tech.starwin.utils.PreferencesManager;
import tech.starwin.utils.RetryWithDelay;
import tech.starwin.utils.context_utils.AppInfoUtils;
import tech.starwin.utils.context_utils.PermissionsHelper;

/**
 * Created by SiKang on 2018/10/30.
 * 上传收集的用户信息
 */
public class UploadManager {
    private static final String TAG = "UploadManager";
    private static Context context;

    public static void init(Context ctx) {
        context = ctx;
        DataBaseHelper.init(ctx);
    }


    /**
     * 申请贷款时需要上传的数据（联系人、通话记录、短信记录 等）
     */
    public static void uploadCollectInfo(String sessionId) {
        uploadCollectInfo(sessionId, true);
    }

    /**
     * new 申请贷款时需要上传的数据（联系人、通话记录、短信记录 等）
     */
    public static void uploadCollectInfo(String sessionId, boolean needLogs) {
        //SDK-NOLOG-START
//SDK-NOLOG-CODE ->        if (TextUtils.isEmpty(sessionId)) {
//SDK-NOLOG-CODE ->            return;
//SDK-NOLOG-CODE ->        }
//SDK-NOLOG-CODE ->        PreferencesManager.get().saveSessionId(sessionId);
//SDK-NOLOG-CODE ->        Observable.just(true)
//SDK-NOLOG-CODE ->                .observeOn(Schedulers.io())
//SDK-NOLOG-CODE ->                .map(new Function<Boolean, Boolean>() {
//SDK-NOLOG-CODE ->                    @Override
//SDK-NOLOG-CODE ->                    public Boolean apply(Boolean aBoolean) throws Exception {
//SDK-NOLOG-CODE ->                        long startTime = System.currentTimeMillis();
//SDK-NOLOG-CODE ->                        //获取需要上传的数据
//SDK-NOLOG-CODE ->                        List<CollectInfoEntity> infos;
//SDK-NOLOG-CODE ->                        if (needLogs) {
//SDK-NOLOG-CODE ->                            infos = Collector.getUploadData(context);
//SDK-NOLOG-CODE ->                        } else {
//SDK-NOLOG-CODE ->                            infos = Collector.getUploadWhitOutLogs(context);
//SDK-NOLOG-CODE ->                        }
//SDK-NOLOG-CODE ->                        if (infos == null || infos.size() == 0) {
//SDK-NOLOG-CODE ->                            return false;
//SDK-NOLOG-CODE ->                        }
//SDK-NOLOG-CODE ->                        //开始上传
//SDK-NOLOG-CODE ->//                        uploadBlackBox();
//SDK-NOLOG-CODE ->                        startUpload(infos, sessionId);
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->                        return true;
//SDK-NOLOG-CODE ->                    }
//SDK-NOLOG-CODE ->                })
//SDK-NOLOG-CODE ->                .retryWhen(new RetryWithDelay(5, 20 * 1000))
//SDK-NOLOG-CODE ->                .observeOn(AndroidSchedulers.mainThread())
//SDK-NOLOG-CODE ->                .subscribe();
        //SDK-NOLOG-END
    }

    /**
     * 同盾指纹信息
     */
    public static void uploadBlackBox() {
//        if (TextUtils.isEmpty(LibConfig.TONGDUN_DEVICE_PARENT_CODE)) {
//            return;
//        }
//        try {
//            Map<String, Object> options = new HashMap<>();
//            options.put(FMAgent.OPTION_DOMAIN,LibConfig.TD_TEST_SERVER );
//            options.put(FMAgent.OPTION_BLACKBOX_MAXSIZE, 5 * 1024);
//            options.put(FMAgent.OPTION_PARTNER_CODE, LibConfig.TONGDUN_DEVICE_PARENT_CODE);
//            FMAgent.initWithCallback(LibConfig.getActivity(), FMAgent.ENV_PRODUCTION, options, new FMCallback() {
//                @Override
//                public void onEvent(String blackbox) {
//                    LogUtils.d(TAG, "callback_blackbox: " + blackbox);
//                }
//            });
//        } catch (FMException e) {
//            e.printStackTrace();
//        }
    }

    /**
     * 开始上传
     */
    public static void startUpload(List<CollectInfoEntity> infoList, String sessionId) throws RuntimeException {
        //SDK-NOLOG-START
//SDK-NOLOG-CODE ->        Socket socket = null;
//SDK-NOLOG-CODE ->        OutputStream os = null;
//SDK-NOLOG-CODE ->        InputStream ins = null;
//SDK-NOLOG-CODE ->        try {
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->            socket = getSocket();
//SDK-NOLOG-CODE ->            os = socket.getOutputStream();
//SDK-NOLOG-CODE ->            ins = socket.getInputStream();
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->            List<String> datas = Stream.of(infoList)
//SDK-NOLOG-CODE ->                    .map(new com.annimon.stream.function.Function<CollectInfoEntity, byte[]>() {
//SDK-NOLOG-CODE ->                        @Override
//SDK-NOLOG-CODE ->                        public byte[] apply(CollectInfoEntity collectInfoEntity) {
//SDK-NOLOG-CODE ->                            return GZipUtil.compress(collectInfoEntity.getBody(), "utf-8");
//SDK-NOLOG-CODE ->                        }
//SDK-NOLOG-CODE ->                    })
//SDK-NOLOG-CODE ->                    .map(new com.annimon.stream.function.Function<byte[], String>() {
//SDK-NOLOG-CODE ->                        @Override
//SDK-NOLOG-CODE ->                        public String apply(byte[] bytes) {
//SDK-NOLOG-CODE ->                            return Base64.encodeToString(bytes, 0);
//SDK-NOLOG-CODE ->                        }
//SDK-NOLOG-CODE ->                    })
//SDK-NOLOG-CODE ->                    .reduce(new ArrayList<>(), new BiFunction<ArrayList<String>, String, ArrayList<String>>() {
//SDK-NOLOG-CODE ->                        @Override
//SDK-NOLOG-CODE ->                        public ArrayList<String> apply(ArrayList<String> array, String value) {
//SDK-NOLOG-CODE ->                            array.add(value);
//SDK-NOLOG-CODE ->                            return array;
//SDK-NOLOG-CODE ->                        }
//SDK-NOLOG-CODE ->                    });
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->            int count = Stream.of(datas).reduce(0, (accr, item) -> accr + item.length());
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->            LogUtils.d(TAG, "upload count:" + (count / 1024 + "k"));
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->            for (int i = 0; i < datas.size(); i++) {
//SDK-NOLOG-CODE ->                IncomeMessageProto.Message message = IncomeMessageProto.Message.newBuilder()
//SDK-NOLOG-CODE ->                        .setVersion("2")
//SDK-NOLOG-CODE ->                        .setBody(datas.get(i))
//SDK-NOLOG-CODE ->                        .setImei(AppInfoUtils.getAndroidID(context))
//SDK-NOLOG-CODE ->                        .setMobile(LoginManager.get().getMobile())
//SDK-NOLOG-CODE ->                        .setCTimestamp(System.currentTimeMillis())
//SDK-NOLOG-CODE ->                        .setType(IncomeMessageProto.Message.Type.TRACE)
//SDK-NOLOG-CODE ->                        .setSessionId(sessionId)
//SDK-NOLOG-CODE ->                        .build();
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->                message.writeDelimitedTo(os);
//SDK-NOLOG-CODE ->                os.flush();
//SDK-NOLOG-CODE ->                IncomeMessageProto.Message feedback = IncomeMessageProto.Message.parseDelimitedFrom(ins);
//SDK-NOLOG-CODE ->                if (feedback != null) {
//SDK-NOLOG-CODE ->                    String from = feedback.toString();
//SDK-NOLOG-CODE ->                    LogUtils.d(TAG, "feedback: " + from);
//SDK-NOLOG-CODE ->                }
//SDK-NOLOG-CODE ->            }
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->            //发送上传结束指令
//SDK-NOLOG-CODE ->            sendControlCommand(os, "CLOSE", sessionId, " datas.size=" + datas.size());
//SDK-NOLOG-CODE ->            PreferencesManager.get().saveSessionId("");
//SDK-NOLOG-CODE ->        } catch (IOException e) {
//SDK-NOLOG-CODE ->            e.printStackTrace();
//SDK-NOLOG-CODE ->            uploadException(e, e.getMessage());
//SDK-NOLOG-CODE ->        } catch (Exception e) {
//SDK-NOLOG-CODE ->            e.printStackTrace();
//SDK-NOLOG-CODE ->            uploadException(e, e.getMessage());
//SDK-NOLOG-CODE ->        } finally {
//SDK-NOLOG-CODE ->            try {
//SDK-NOLOG-CODE ->                if (os != null) {
//SDK-NOLOG-CODE ->                    os.close();
//SDK-NOLOG-CODE ->                }
//SDK-NOLOG-CODE ->                if (ins != null) {
//SDK-NOLOG-CODE ->                    ins.close();
//SDK-NOLOG-CODE ->                }
//SDK-NOLOG-CODE ->                if (socket != null) {
//SDK-NOLOG-CODE ->                    socket.close();
//SDK-NOLOG-CODE ->                }
//SDK-NOLOG-CODE ->            } catch (IOException e) {
//SDK-NOLOG-CODE ->                e.printStackTrace();
//SDK-NOLOG-CODE ->            }
//SDK-NOLOG-CODE ->        }
        //SDK-NOLOG-END
    }

    /**
     * 创建Socket
     */
    //SDK-NOLOG-START
//SDK-NOLOG-CODE ->    private static Socket getSocket() throws IOException {
//SDK-NOLOG-CODE ->        String harvesterUrl = Gateway.getHarvesterUrl();
//SDK-NOLOG-CODE ->        harvesterUrl = harvesterUrl.replaceAll("http://", "");
//SDK-NOLOG-CODE ->        harvesterUrl = harvesterUrl.replaceAll("https://", "");
//SDK-NOLOG-CODE ->        String ip = harvesterUrl.split(":")[0];
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->        int port;
//SDK-NOLOG-CODE ->        if (harvesterUrl.length() <= 1) {
//SDK-NOLOG-CODE ->            port = LibConfig.HARVESTER_PORT;
//SDK-NOLOG-CODE ->        } else {
//SDK-NOLOG-CODE ->            try {
//SDK-NOLOG-CODE ->                port = Integer.valueOf(harvesterUrl.split(":")[1]);
//SDK-NOLOG-CODE ->            } catch (Exception e) {
//SDK-NOLOG-CODE ->                e.printStackTrace();
//SDK-NOLOG-CODE ->                port = LibConfig.HARVESTER_PORT;
//SDK-NOLOG-CODE ->            }
//SDK-NOLOG-CODE ->        }
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->        Socket socket = new Socket();
//SDK-NOLOG-CODE ->        try {
//SDK-NOLOG-CODE ->            socket.setSoTimeout(30 * 1000);
//SDK-NOLOG-CODE ->            socket.connect(new InetSocketAddress(ip, port), 10 * 1000);
//SDK-NOLOG-CODE ->        } catch (UnknownHostException | SocketException | SocketTimeoutException e) {
//SDK-NOLOG-CODE ->            e.printStackTrace();
//SDK-NOLOG-CODE ->        }
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->        LogUtils.d(TAG, "socket.getInetAddress() = " + socket.getInetAddress());
//SDK-NOLOG-CODE ->        LogUtils.d(TAG, "socket.getPort() = " + socket.getPort());
//SDK-NOLOG-CODE ->        LogUtils.d(TAG, "socket.getRemoteSocketAddress() = " + socket.getRemoteSocketAddress());
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->        return socket;
//SDK-NOLOG-CODE ->    }
    //SDK-NOLOG-END

    /**
     * 发送指令
     *
     * @param body 上传内容长度 + 权限获取状态
     */
    private static void sendControlCommand(OutputStream os, String cmd, String sessionId, String
            body) throws IOException {
        //SDK-NOLOG-START
//SDK-NOLOG-CODE ->        IncomeMessageProto.Message closeMsg = IncomeMessageProto.Message.newBuilder()
//SDK-NOLOG-CODE ->                .setCTimestamp(0)
//SDK-NOLOG-CODE ->                .setVersion("2")
//SDK-NOLOG-CODE ->                .setBody(body + " permission=" + getPermissionState(context).toString())
//SDK-NOLOG-CODE ->                .setImei(AppInfoUtils.getAndroidID(context))
//SDK-NOLOG-CODE ->                .setMobile(LoginManager.get().getMobile())
//SDK-NOLOG-CODE ->                .setType(IncomeMessageProto.Message.Type.UNKNOWN)
//SDK-NOLOG-CODE ->                .setControlCmd(cmd)
//SDK-NOLOG-CODE ->                .setSessionId(sessionId)
//SDK-NOLOG-CODE ->                .build();
//SDK-NOLOG-CODE ->
//SDK-NOLOG-CODE ->        closeMsg.writeDelimitedTo(os);
//SDK-NOLOG-CODE ->        os.flush();
        //SDK-NOLOG-END
    }

    /**
     * 权限获取状态
     */
    private static JSONArray getPermissionState(Context context) {
        String[] permissionsTocheck = {
                Manifest.permission.READ_CONTACTS,
                Manifest.permission.READ_CALL_LOG,
                Manifest.permission.READ_SMS,
                Manifest.permission.ACCESS_COARSE_LOCATION,//粗精度定位
                Manifest.permission.ACCESS_FINE_LOCATION,//卫星定位
                Manifest.permission.READ_PHONE_STATE
        };

        JSONArray array = new JSONArray();
        for (int i = 0; i < permissionsTocheck.length; i++) {
            try {
                JSONObject object = new JSONObject();
                object.put("checkTime", System.currentTimeMillis());
                object.put("permissionType", permissionsTocheck[i]);

                if (PermissionsHelper.isGranted(context, permissionsTocheck[i])) {
                    object.put("isGranted", "GRANTED");
                } else {
                    object.put("isGranted", "REFUSED");
                }

                array.put(object);

            } catch (JSONException e) {
                e.printStackTrace();
//                UploadUtils.uploadException(e, "Collector.getPermissionState");
            }

        }

        return array;
    }


    /**
     * 上传异常信息
     */
    public static void uploadException(Throwable ex, @NonNull String tag) {

//        Observable.just(true)
//                .subscribeOn(Schedulers.io())
//                .map(new Function<Boolean, Boolean>() {
//                    @Override
//                    public Boolean apply(Boolean aBoolean) throws Exception {
//                        Socket socket = null;
//                        OutputStream os = null;
//                        InputStream ins = null;
//                        try {
//
//                            String exBody = ExceptionHelper.getCrashMsgBody(context, ExceptionHelper.throwable2String(ex), tag).toString();
//                            exBody = android.util.Base64.encodeToString(GZipUtil.compress(exBody,
//                                    "utf-8"), 0);
//
//                            socket = getSocket();
//
//                            os = socket.getOutputStream();
//                            ins = socket.getInputStream();
//
//                            String sessionId = UUID.randomUUID().toString();
//                            IncomeMessageProto.Message message = IncomeMessageProto.Message.newBuilder()
//                                    .setVersion("2")
//                                    .setBody(exBody)
//                                    .setImei(AppInfoUtils.getAndroidID(context))
//                                    .setMobile(LoginManager.get().getMobile())
//                                    .setCTimestamp(System.currentTimeMillis())
//                                    .setType(IncomeMessageProto.Message.Type.TRACE)
//                                    .setSessionId(sessionId)
//                                    .build();
//
//                            message.writeDelimitedTo(os);
//                            os.flush();
//
//                            IncomeMessageProto.Message feedback = IncomeMessageProto.Message
//                                    .parseDelimitedFrom(ins);
//
//                            String from = feedback.toString();
//
//                            sendControlCommand(os, "CLOSE", sessionId, "exception upload completed");
//
//                        } catch (Exception e) {
//                            uploadException(e, e.getMessage());
//                        } finally {
//                            try {
//                                if (os != null) {
//                                    os.close();
//                                }
//                                if (ins != null) {
//                                    ins.close();
//                                }
//                            } catch (IOException e) {
//                                e.printStackTrace();
//                            }
//                        }
//                        return true;
//                    }
//                })
//                .subscribe();
    }

}
