package home.smart.fly.http.activity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;

import java.util.concurrent.TimeUnit;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import home.smart.fly.http.R;
import home.smart.fly.http.R2;
import home.smart.fly.http.model.GankAndroid;
import home.smart.fly.http.model.GankApi;
import home.smart.fly.proxy.ApiGenerator;
import home.smart.fly.transformer.SimpleRequestResponseTransformer;
import home.smart.fly.transformer.SimpleRequestTransformer;
import io.reactivex.Completable;
import io.reactivex.CompletableEmitter;
import io.reactivex.CompletableObserver;
import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.plugins.RxJavaPlugins;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * @author Rookie
 */
public class RxJavaBaseActivity extends RxAppCompatActivity {
    private static final String BASE_URL = "http://gank.io/api/";

    private static final String TAG = "RxJavaBaseActivity";
    @BindView(R2.id.basic1)
    Button mBasic1;
    @BindView(R2.id.basic2)
    Button mBasic2;
    @BindView(R2.id.basic3)
    Button mBasic3;
    @BindView(R2.id.basic4)
    Button mBasic4;
    @BindView(R2.id.basic5)
    Button mBasic5;
    @BindView(R2.id.logContent)
    TextView logContent;


    private StringBuilder sb = new StringBuilder();
    private CompositeDisposable mCompositeDisposable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rx_java_base);
        ButterKnife.bind(this);
        mCompositeDisposable = new CompositeDisposable();

        RxJavaPlugins.setErrorHandler(throwable -> Log.e(TAG, "throwable: " + throwable.getMessage()));
    }

    @OnClick({R2.id.basic1, R2.id.basic2,
            R2.id.basic3, R2.id.basic4,
            R2.id.basic5, R2.id.basic6,
            R2.id.basic7, R2.id.basic8,
            R2.id.basic9, R2.id.basic10,
            R2.id.basic11})
    public void onClick(View v) {
        if (sb != null) {
            sb = null;
        }
        sb = new StringBuilder();
        logContent.setText("");

        if (v.getId() == R.id.basic1) {
            basicRxjava2();
        } else if (v.getId() == R.id.basic2) {
            basicRxjava2Chian();
        } else if (v.getId() == R.id.basic3) {
            consumer();
        } else if (v.getId() == R.id.basic4) {
            thread();
        } else if (v.getId() == R.id.basic5) {
            multiThread();
        } else if (v.getId() == R.id.basic6) {
            withRetrofit2();
        } else if (v.getId() == R.id.basic7) {
            withRetrofit2AndGson();
        } else if (v.getId() == R.id.basic8) {
            onlysubscribe();
        } else if (v.getId() == R.id.basic9) {
            completable();
        } else if (v.getId() == R.id.basic10) {
            useSimpleRequest();
        } else if (v.getId() == R.id.basic11) {
            lambdaObserverTest();
        }
    }

    @SuppressWarnings("checkResult")
    private void lambdaObserverTest() {
        Observable.create((ObservableOnSubscribe<String>) emitter -> {
            emitter.onError(new Throwable("just test"));
        }).subscribe(s -> Log.e(TAG, "accept: " + s));

//        RxJavaPlugins.setErrorHandler(throwable -> Log.e(TAG, "accept: error handle by at here"));
    }

    @SuppressLint("CheckResult")
    private void useSimpleRequest() {
        GankApi api = ApiGenerator.generatorApi(GankApi.class);
        api.getDataResponse("10/1")
                .compose(new SimpleRequestResponseTransformer<GankAndroid>(bindToLifecycle()) {
                    @Override
                    public void onRequestFailure(Throwable throwable) {
                        Toast.makeText(RxJavaBaseActivity.this, "fail" + throwable.getMessage(), Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onRequestSuccess(GankAndroid result) {
                        GankAndroid.ResultsEntity resultsEntity = result.getResults().get(0);
                        sb.append(resultsEntity.getCreatedAt()).append("\n")
                                .append(resultsEntity.getType()).append("\n")
                                .append(resultsEntity.getDesc()).append("\n")
                                .append(resultsEntity.getUrl()).append("\n")
                                .append(resultsEntity.getWho());

                        logContent.setText(sb.toString());
                    }
                });
    }

    private void completable() {
        Completable.create(CompletableEmitter::onComplete).compose(new SimpleRequestTransformer<>())
                .subscribe(new CompletableObserver() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onComplete() {
                        Log.e(TAG, "onComplete: ");
                    }

                    @Override
                    public void onError(Throwable e) {

                    }
                });

    }


    private void withRetrofit2AndGson() {
        final OkHttpClient mClient = new OkHttpClient.Builder()
                .readTimeout(10, TimeUnit.SECONDS)
                .connectTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                .build();

        final Retrofit mRetrofit = new Retrofit.Builder()
                .client(mClient)
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();

        GankApi mGankApi = mRetrofit.create(GankApi.class);
        Observable<GankAndroid> mAndroidObservable = mGankApi.getData("10/1");
        mCompositeDisposable.add(mAndroidObservable
                .subscribeOn(Schedulers.io())
                .map(gankAndroid -> gankAndroid.getResults().get(0))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(resultsEntity -> {
                    sb.append(resultsEntity.getCreatedAt()).append("\n")
                            .append(resultsEntity.getType()).append("\n")
                            .append(resultsEntity.getDesc()).append("\n")
                            .append(resultsEntity.getUrl()).append("\n")
                            .append(resultsEntity.getWho());

                    logContent.setText(sb.toString());
                }));

    }

    private void withRetrofit2() {
        OkHttpClient.Builder mBuilder = new OkHttpClient.Builder();
        mBuilder.readTimeout(10, TimeUnit.SECONDS);
        mBuilder.connectTimeout(30, TimeUnit.SECONDS);

        HttpLoggingInterceptor mLoggingInterceptor = new HttpLoggingInterceptor();
        mLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        mBuilder.addInterceptor(mLoggingInterceptor);

        OkHttpClient mClient = mBuilder.build();

        Retrofit.Builder builder = new Retrofit.Builder();
        builder.baseUrl(BASE_URL);
        builder.client(mClient);

        Retrofit mRetrofit = builder.build();

        final GankApi mGankApi = mRetrofit.create(GankApi.class);
        final Call<ResponseBody> mCall = mGankApi.getJson("10/1");

        Observable.create((ObservableOnSubscribe<ResponseBody>) e -> e.onNext(mCall.execute().body()))
                .map(ResponseBody::string)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.e(TAG, "onSubscribe: d=" + d);
                    }

                    @Override
                    public void onNext(String s) {
                        logContent.setText(s);
                    }

                    @Override
                    public void onError(Throwable e) {
                        logContent.setText(e.toString());
                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }


    private void multiThread() {
        mCompositeDisposable.add(Observable.create((ObservableOnSubscribe<String>) e -> {
            e.onNext("This msg from work thread :" + Thread.currentThread().getName());
            sb.append("\nsubscribe: currentThreadName==").append(Thread.currentThread().getName());
        })
                .subscribeOn(Schedulers.newThread())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(s -> {
                    Log.e(TAG, "accept: s= " + s);
                    Log.e(TAG, "accept: currentThreadName==" + Thread.currentThread().getName());

                    sb.append("\naccept: currentThreadName==").append(Thread.currentThread().getName());
                    sb.append("\n\n简单的来说, subscribeOn() 指定的是上游发送事件的线程, observeOn() 指定的是下游接收事件的线程.\n" +
                            "\n" +
                            "多次指定上游的线程只有第一次指定的有效, 也就是说多次调用subscribeOn() 只有第一次的有效, 其余的会被忽略.\n" +
                            "多次指定下游的线程是可以的, 也就是说每调用一次observeOn() , 下游的线程就会切换一次.");
                    logContent.setText(sb.toString());
                }));
    }

    private void thread() {
        Observable<String> mObservable = Observable.create(e -> {
            Log.e(TAG, "subscribe: currentThreadName==" + Thread.currentThread().getName());
            sb.append("\nsubscribe: currentThreadName==").append(Thread.currentThread().getName());
            e.onNext("1000");
        });

        Consumer<String> mConsumer = s -> {
            Log.e(TAG, "accept: currentThreadName==" + Thread.currentThread().getName());
            Log.e(TAG, "accept: s=" + s);

            sb.append("\naccept: currentThreadName==").append(Thread.currentThread().getName());
            logContent.setText(sb.toString());
        };

        mCompositeDisposable.add(mObservable.subscribe(mConsumer));
    }

    private void consumer() {
        mCompositeDisposable.add(Observable.create((ObservableOnSubscribe<String>) e -> {
            e.onNext("Hello World");
            e.onError(new Throwable("Some Thing wrong !"));
        }).subscribe(s -> {
            Log.e(TAG, "accept: s=" + s);
            logContent.setText(s);
        }, throwable -> {
            Log.e(TAG, "accept: throwable=" + throwable.toString());
            logContent.setText(throwable.toString());
        }));
    }


    private void basicRxjava2() {

        Observable<String> mObservable = Observable.create(e -> {
            e.onNext("1");
            e.onNext("2");
            e.onNext("3");
            e.onNext("4");
            e.onComplete();
        });


        Observer<String> mObserver = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.e(TAG, "onSubscribe: d=" + d);
                sb.append("\nonSubcribe: d=").append(d);
            }

            @Override
            public void onNext(String s) {
                Log.e(TAG, "onNext: " + s);
                sb.append("\nonNext: ").append(s);
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: " + e);
                sb.append("\nonError: ").append(e.toString());
                logContent.setText(sb.toString());
            }

            @Override
            public void onComplete() {
                Log.e(TAG, "onComplete");
                sb.append("\nonComplete: ");
                logContent.setText(sb.toString());
            }
        };

        mObservable.subscribe(mObserver);
    }

    private void onlysubscribe() {
        Observable.create((ObservableOnSubscribe<String>) emitter -> {
            emitter.onNext("A");
            throw new Exception("I'm just a test");
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(String s) {

            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: e==" + e.toString());
            }

            @Override
            public void onComplete() {

            }
        });
    }


    private void basicRxjava2Chian() {

        Observable.create((ObservableOnSubscribe<String>) e -> {
            e.onNext("A");
            e.onNext("B");
            e.onNext("C");
            e.onNext("D");
            e.onComplete();
            e.onNext("E");
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.e(TAG, "onSubscribe: d=" + d);
                sb.append("\nonSubcribe: d=").append(d);

            }

            @Override
            public void onNext(String s) {
                Log.e(TAG, "onNext: " + s);
                sb.append("\nonNext: ").append(s);
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: " + e);
                sb.append("\nonError: ").append(e.toString());
                logContent.setText(sb.toString());
            }

            @Override
            public void onComplete() {
                Log.e(TAG, "onComplete");
                sb.append("\nonComplete: ");
                logContent.setText(sb.toString());
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mCompositeDisposable != null) {
            mCompositeDisposable.dispose();
        }
    }
}