package com.ysnows.base.ccretrofit;

import android.content.Context;

import com.billy.cc.core.component.CC;
import com.billy.cc.core.component.CCResult;
import com.ysnows.base.ccretrofit.annotation.Async;
import com.ysnows.base.ccretrofit.annotation.MainThread;
import com.ysnows.base.ccretrofit.annotation.Param;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.WeakHashMap;

import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;

public class CCRetrofit implements InvocationHandler {


    private static CCRetrofit ccRetrofit;
    private WeakHashMap<String, Object> weakHashMap = new WeakHashMap<>();
    private Context context = null;

    public static CCRetrofit instance() {
        if (ccRetrofit == null) {
            ccRetrofit = new CCRetrofit();
        }
        return ccRetrofit;
    }

    public CCRetrofit with(Context cont) {
        context = cont;
        return this;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        String className = method.getDeclaringClass().getSimpleName();//className用作CC component的name
        String methodName = method.getName();
        CC.Builder builder;
        if (null != context) {
            builder = CC.obtainBuilder(className)
                    .setContext(context)
                    .setActionName(methodName);
        } else {
            builder = CC.obtainBuilder(className)
                    .setActionName(methodName);
        }

        Annotation[][] parameterAnnotations = method.getParameterAnnotations();

        if (args != null) {
            for (int i = 0; i < args.length; i++) {//遍历参数，成CC的Param
                Object arg = args[i];
                if (parameterAnnotations.length > i) {//防止出现没有@Param的情况
                    Param param = (Param) parameterAnnotations[i][0];
                    builder.addParam(param.value(), arg);
                }
            }
        }

        Async async = method.getAnnotation(Async.class);

        if (async == null) {

            return Observable.create((ObservableOnSubscribe<CCResult>) emitter -> {
                CCResult ccResult = builder
                        .build()
                        .call();
                emitter.onNext(ccResult);
            });
        } else {
            MainThread mainThread = method.getAnnotation(MainThread.class);

            if (mainThread != null) {
                return Observable.create((ObservableOnSubscribe<CCResult>) emitter -> builder
                        .build()
                        .callAsyncCallbackOnMainThread((cc, result) -> emitter.onNext(result)));
            } else {
                return Observable.create((ObservableOnSubscribe<CCResult>) emitter -> builder
                        .build()
                        .callAsync((cc, result) -> emitter.onNext(result)));
            }
        }
    }

    public <T extends IRoute> T create(Class<T> route) {
        T instance;
        if (!weakHashMap.containsKey(route.getName())) {
            instance = (T) Proxy.newProxyInstance(route.getClassLoader(), new Class[]{route}, this);
            weakHashMap.put(route.getName(), instance);
        }
        return (T) weakHashMap.get(route.getName());
    }

}
