package com.p3.bewoplaner.data.api;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import com.p3.bewoplaner.BewoplanerApplication;
import com.p3.bewoplaner.BuildConfig;
import com.p3.bewoplaner.data.AppPrefsConstants;
import com.p3.bewoplaner.data.prefs.StringPreference;
import com.p3.bewoplaner.di.P3DSEndpoint;
import com.p3.bewoplaner.di.VoucherEndpoint;
import com.p3.bewoplaner.di.scopes.ApplicationScope;
import com.p3.bewoplaner.utils.Constants;

import java.io.File;
import java.util.concurrent.TimeUnit;

import javax.inject.Named;

import dagger.Module;
import dagger.Provides;
import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.CallAdapter;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.schedulers.Schedulers;

/**
 * Created by laszloffiferenc on 2/21/17.
 */
@Module
public class ApiModule {

    @Provides
    @ApplicationScope
    Cache provideCache(BewoplanerApplication app) {
        File httpCacheDirectory = new File(app.getCacheDir().getAbsolutePath(), "HttpCache");
        return new Cache(httpCacheDirectory, Constants.DISK_CACHE_SIZE);
    }

    @Provides
    @ApplicationScope
    HttpLoggingInterceptor provideLoggingInterceptor() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        if (BuildConfig.DEBUG) {
            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        } else {
            interceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
        }
        return interceptor;
    }

    @Provides
    @ApplicationScope
    Interceptor provideHeaderInterceptor(@Named(AppPrefsConstants.LOGIN_TOKEN) final StringPreference token, @Named(AppPrefsConstants.ACCOUNT_NO) final StringPreference customerId) {
        return chain -> {
            final boolean isHeaderSet = token.isSet() || customerId.isSet();
            Request original = chain.request();
            Request.Builder builder = original.newBuilder();
            if (token.isSet()) {
                builder.addHeader("Token", token.get());
            }
            if (customerId.isSet()) {
                builder.addHeader("CustomerID", customerId.get());
            }
            if (isHeaderSet) {
                return chain.proceed(builder.build());
            }
            return chain.proceed(original.newBuilder().build());
        };
    }

    @Provides
    @ApplicationScope
    @P3DSEndpoint
    OkHttpClient provideP3DSOkHttpClient(Cache cache,
                                         HttpLoggingInterceptor loggingInterceptor,
                                         Interceptor interceptor) {
        return new OkHttpClient.Builder()
                .cache(cache)
                .connectTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(loggingInterceptor)
                .addInterceptor(interceptor)
                .build();
    }

    @Provides
    @ApplicationScope
    @VoucherEndpoint
    OkHttpClient provideVoucherkHttpClient(Cache cache,
                                           HttpLoggingInterceptor loggingInterceptor) {
        return new OkHttpClient.Builder()
                .cache(cache)
                .addInterceptor(loggingInterceptor)
                .build();
    }

    @Provides
    @ApplicationScope
    CallAdapter.Factory provideCallAdapterFactory() {
        return RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io());
    }

    @Provides
    @ApplicationScope
    Gson provideGson() {
        return new GsonBuilder()
                .setDateFormat("yyyy-MM-dd HH:mm:ss")
                .create();
    }

    @Provides
    @ApplicationScope
    Converter.Factory provideConverterFactory(Gson gson) {
        return GsonConverterFactory.create(gson);
    }

    @Provides
    @ApplicationScope
    @P3DSEndpoint
    Retrofit provideP3DSRetrofit(@P3DSEndpoint final OkHttpClient okHttpClient,
                                 @Named(AppPrefsConstants.API_ENDPOINT) final StringPreference endpoint,
                                 final Converter.Factory converter,
                                 final CallAdapter.Factory adapterFactory) {
        return new Retrofit.Builder()
                .baseUrl(endpoint.get() == null ? Constants.BEWOPLANER_ENDPOINT : endpoint.get())
                .addCallAdapterFactory(adapterFactory)
                .addConverterFactory(converter)
                .client(okHttpClient)
                .build();
    }

    @Provides
    @ApplicationScope
    @VoucherEndpoint
    Retrofit provideVoucherRetrofit(@VoucherEndpoint final OkHttpClient okHttpClient,
                                    final Converter.Factory converter,
                                    final CallAdapter.Factory adapterFactory) {
        return new Retrofit.Builder()
                .baseUrl(Constants.VOUCHER_ENDPOINT)
                .addCallAdapterFactory(adapterFactory)
                .addConverterFactory(converter)
                .client(okHttpClient)
                .build();
    }
}