package com.davidmedenjak.redditsample.app;

import androidx.annotation.NonNull;

import com.davidmedenjak.auth.manager.OAuthAccountManager;
import com.davidmedenjak.auth.okhttp.RequestAuthInterceptor;
import com.davidmedenjak.auth.okhttp.RequestRetryAuthenticator;
import com.davidmedenjak.redditsample.auth.api.RedditAuthApi;
import com.davidmedenjak.redditsample.networking.RedditApi;
import com.squareup.moshi.Moshi;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.moshi.MoshiConverterFactory;

public class HttpModule {

    private final App app;

    private OkHttpClient client;
    private Moshi moshi;

    private RedditAuthApi authService;
    private RedditApi apiService;

    public HttpModule(App app) {
        this.app = app;
    }

    @NonNull
    public OkHttpClient provideOkHttp() {
        if (client == null) {
            synchronized (this) {
                if (client == null) {
                    HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
                    logger.setLevel(HttpLoggingInterceptor.Level.BODY);
                    client = new OkHttpClient.Builder().addNetworkInterceptor(logger).build();
                }
            }
        }
        return client;
    }

    @NonNull
    public Moshi provideMoshi() {
        if (moshi == null) {
            synchronized (this) {
                if (moshi == null) {
                    moshi = new Moshi.Builder().build();
                }
            }
        }
        return moshi;
    }

    // we need 2 different api services - one for login & authentication (that doesn't try to add
    // `Authorization` headers) and one for our authenticated calls.

    // adding the interceptors to the auth api service as well would result in a deadlock as they
    // would
    // try to fetch an access token while fetching an access token.

    public RedditAuthApi getAuthApiService() {
        if (authService == null) {
            synchronized (this) {
                if (authService == null) {
                    MoshiConverterFactory converterFactory =
                            MoshiConverterFactory.create(provideMoshi());
                    authService =
                            new Retrofit.Builder()
                                    .client(provideOkHttp())
                                    .addConverterFactory(converterFactory)
                                    .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync())
                                    .baseUrl("https://www.reddit.com/api/")
                                    .build()
                                    .create(RedditAuthApi.class);
                }
            }
        }
        return authService;
    }

    public RedditApi getApiService() {
        if (apiService == null) {
            synchronized (this) {
                if (apiService == null) {
                    OAuthAccountManager authenticator = app.getAccountManager();
                    final OkHttpClient okHttpClient =
                            provideOkHttp()
                                    .newBuilder()
                                    // add authenticators only here to prevent deadlocks when
                                    // (re-)authenticating
                                    .authenticator(new RequestRetryAuthenticator(authenticator))
                                    .addInterceptor(new RequestAuthInterceptor(authenticator))
                                    .build();
                    MoshiConverterFactory converterFactory =
                            MoshiConverterFactory.create(provideMoshi());
                    apiService =
                            new Retrofit.Builder()
                                    .client(okHttpClient)
                                    .addConverterFactory(converterFactory)
                                    .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync())
                                    .baseUrl("https://oauth.reddit.com/api/")
                                    .build()
                                    .create(RedditApi.class);
                }
            }
        }
        return apiService;
    }
}