package org.telegram.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.jakewharton.processphoenix.ProcessPhoenix;

import org.telegram.io.Constants;
import org.telegram.io.CryptLib;
import org.telegram.io.Proxy;
import org.telegram.io.SingletonSocket;
import org.telegram.io.Utils;
import org.telegram.tgnet.ConnectionsManager;

import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.crypto.NoSuchPaddingException;

import io.socket.emitter.Emitter;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;


/**
 * Created by Ahmad Nemati on 1/17/19.
 */
public class SocketService extends Service implements Emitter.Listener {
    private Gson gson;
    private CryptLib cryptLib;
    private static final String key = "6*sN_rZxHD4!X$=T";
    ConnectionsManager connectionsManager;
    Boolean work = false;


    @Override
    public void onCreate() {
        super.onCreate();
        gson = new Gson();
        connectionsManager = new ConnectionsManager();
        try {
            cryptLib = new CryptLib();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
        SingletonSocket.getInstance().getSocket().on(Constants.GET_JSON_FOR_PING, this);
        SingletonSocket.getInstance().getSocket().connect();

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void call(Object... args) {

        if (args.length == 0 || work) return;


        Log.e("Ping from server Size", String.valueOf(args.length));
        String chiper = String.valueOf(args[0]);

        try {
            String decrypt = cryptLib.decryptCipherTextWithRandomIV(chiper, key);
            List<Proxy> proxyList = gson.fromJson(decrypt, new TypeToken<List<Proxy>>() {
            }.getType());
            proxyList = Utils.removeDuplicator(proxyList);
            Log.e("PingSizeOfRes", String.valueOf(proxyList.size()));
            work = true;
            initCheckProxy(proxyList);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }


    public Observable<Proxy> getPingServerObservable(Proxy proxy) {


        return Observable.create(subscriber -> {
            ConnectionsManager.setProxySettings(proxy.getIp(), proxy.getPort(), proxy.getSecret());
            connectionsManager.checkProxy(proxy.getIp(), proxy.getPort(), proxy.getSecret()
                    , time -> {
                        proxy.setPing(time == -1 ? 0 : time);
                        subscriber.onNext(proxy);
                        subscriber.onCompleted();
                    });
        });


    }

    


    public void initCheckProxy(List<Proxy> proxyList) {


        Observable.from(proxyList)
                .subscribeOn(Schedulers.io())
                .concatMap(proxy -> getPingServerObservable(proxy)
                        .subscribeOn(Schedulers.io())
                        .timeout(10, TimeUnit.SECONDS)
                        .onErrorResumeNext(t ->

                        {
                            proxy.setPing(0);
                            return Observable.just(proxy);
                        }))
                .toList()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<List<Proxy>>() {
                    @Override
                    public void onCompleted() {
                        work = false;
                    }

                    @Override
                    public void onError(Throwable e) {
                        work = false;
                    }

                    @Override
                    public void onNext(List<Proxy> proxyList) {
                        int w = 0;
                        int n = 0;
                        Boolean needReset = true;
                        for (Proxy proxy : proxyList) {
                            if (proxy.getPing() > 0) {
                                needReset = false;
                                w++;
                            } else
                                n++;
                        }
                        if (needReset)
                            ProcessPhoenix.triggerRebirth(SocketService.this);

                        work = false;
                        Log.e("Ping", "Task Check Finished for " + proxyList.size() + " Ips And " + w + " Ips Work and " + n + " IPS not work");

                        try {
                            String cipherText = cryptLib.encryptPlainTextWithRandomIV(gson.toJson(proxyList), key);
                            SingletonSocket.getInstance().getSocket().emit("checkping", cipherText);

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


    }


}
