package com.bxzk.afxj.retrofit;

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;

public class RxBus {
    private HashMap<String, CompositeDisposable> mSubscriptionMap;
    private HashMap<String, Object> mObjectMap;
    private static volatile RxBus mRxBus;
    private final Subject<Object> mSubject;
    private final Map<Class<?>, Object> mStickyEventMap;

    public RxBus() {
        mSubject = PublishSubject.create().toSerialized();
        mObjectMap = new HashMap<String, Object>();
        mStickyEventMap = new ConcurrentHashMap<>();
    }

    /**
     * 发送一个新Sticky事件
     */
    public void postSticky(Object event) {
        synchronized (mStickyEventMap) {
            mStickyEventMap.put(event.getClass(), event);
        }
        post(event);
    }

    /**
     * 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
     */
    public <T> Disposable doSubscribeSticky(final Class<T> eventType,Consumer<T> next, Consumer<Throwable> error) {
        synchronized (mStickyEventMap) {
                return getObservable(eventType).mergeWith(new Publisher<T>() {
                    @Override
                    public void subscribe(Subscriber<? super T> s) {
                        final Object event = mStickyEventMap.get(eventType);
                        if(event !=null) {
                            s.onNext(eventType.cast(event));
                            s.onComplete();
                        }else {
                        }

                    }
                }).subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(next,error);
        }
    }


    public void post(Object o) {
        mSubject.onNext(o);
    }

    public void postByTag(String tag, Object o) {
        mObjectMap.put(tag, o);
        mSubject.onNext(o);
    }

    public <T> Disposable doSubscribeByTag(String tag, Class<T> type, Consumer<T> next, Consumer<Throwable> error) {
        return getObservable(type)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .map((Function<Object, T>) o -> {
                    Object o1;
                    if (mObjectMap.containsKey(tag)) {
                        o1 = mObjectMap.get(tag);
                        mObjectMap.remove(tag);
                        T t = (T) o;
                        return t;
                    }else {
                        return null;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(next, error);
    }

    /**
     * 返回指定类型的带背压的Flowable实例
     *
     * @param <T>
     * @param type
     * @return
     */
    public <T> Flowable<T> getObservable(Class<T> type) {

        return mSubject.toFlowable(BackpressureStrategy.BUFFER)
                .ofType(type);
    }

    public <T> Observable<T> toObservable(Class<T> tClass) {
        return mSubject.ofType(tClass);
    }

    /**
     * 一个默认的订阅方法
     *
     * @param <T>
     * @param type 事件class类型
     * @param next  接收成功的回调
     * @param error 接收失败的回调
     * @return
     */
    public <T> Disposable doSubscribe(Class<T> type, Consumer<T> next, Consumer<Throwable> error) {
        Disposable subscribe = getObservable(type)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(next, error);
        return subscribe;
    }

    /**
     * 是否已有观察者订阅
     *
     * @return
     */
    public boolean hasObservers() {
        return mSubject.hasObservers();
    }

    /**
     * 根据eventType获取Sticky事件
     */
    public <T> T getStickyEvent(Class<T> eventType) {
        synchronized (mStickyEventMap) {
            return eventType.cast(mStickyEventMap.get(eventType));
        }
    }

    /**
     * 移除指定eventType的Sticky事件
     */
    public <T> T removeStickyEvent(Class<T> eventType) {
        synchronized (mStickyEventMap) {
            return eventType.cast(mStickyEventMap.remove(eventType));
        }
    }

    /**
     *在主act 移除所有的Sticky事件 还有tag
     */
    public void removeAllStickyEvents() {
        synchronized (mStickyEventMap) {
            mStickyEventMap.clear();
            mObjectMap.clear();
        }
    }

    /**
     * 保存订阅后的disposable
     *
     * @param o
     * @param disposable
     */
    public void addSubscription(Object o, Disposable disposable) {
        if (disposable != null) {
            if (mSubscriptionMap == null) {
                mSubscriptionMap = new HashMap<>();
            }
            String key = o.getClass().getName();
            if (mSubscriptionMap.get(key) != null) {
                mSubscriptionMap.get(key).add(disposable);
            } else {
                //一次性容器,可以持有多个并提供 添加和移除。
                CompositeDisposable disposables = new CompositeDisposable();
                disposables.add(disposable);
                mSubscriptionMap.put(key, disposables);
            }
        }
    }

    /**
     * 取消订阅
     *
     * @param o
     */
    public void unSubscribe(Object o) {
        if (mSubscriptionMap == null) {
            return;
        }

        String key = o.getClass().getName();
        if (!mSubscriptionMap.containsKey(key)) {
            return;
        }
        if (mSubscriptionMap.get(key) != null) {
            mSubscriptionMap.get(key).dispose();
        }

        mSubscriptionMap.remove(key);
    }
}
