package com.androidstudy.andelatrackchallenge.network;

import android.support.v4.util.ObjectsCompat;
import android.text.TextUtils;

import com.androidstudy.andelatrackchallenge.models.Country;
import com.androidstudy.andelatrackchallenge.models.Exchange;
import com.androidstudy.andelatrackchallenge.models.History;
import com.squareup.moshi.Moshi;

import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.moshi.MoshiConverterFactory;
import timber.log.Timber;

/**
 * Created by anonymous on 10/10/17.
 */

/**
 * This class will help us create a re-usable Retrofit Client and composing parts,
 * to avoid repeating our code!
 */
public class ApiClient {
    public static final String BTC_ETH = "BTC,ETH";
    public static final String BTC = "BTC";
    public static final String ETH = "ETH";

    private static Api api;
    private static Retrofit retrofit;
    private static OkHttpClient client;

    public static Retrofit getClient() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(URLs.BASE_URL)
                    .client(getOkClient())
                    .addConverterFactory(MoshiConverterFactory.create(getMoshi()))
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
        }
        return retrofit;
    }

    public static Api getApi() {
        if (api == null) {
            api = getClient().create(Api.class);
        }
        return api;
    }

    public static Moshi getMoshi() {
        return new Moshi.Builder()
                .build();
    }

    public static OkHttpClient getOkClient() {
        if (client == null) {
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> Timber.i(message));
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);

            client = new OkHttpClient.Builder()
                    .addInterceptor(logging)
                    .build();
        }
        return client;
    }

    public static Single<Country> loadRate(Country oldCountry) {
        long minutesBefore = System.currentTimeMillis() - (10 * 60 * 1000);
        if (oldCountry.refreshedAt > minutesBefore)
            return Single.error(new Throwable("No refresh needed!"));

        return getApi().getPrice(oldCountry.code, BTC_ETH)
                .map(response -> {
                    HttpUrl url = response.raw().request().url();
                    String from = url.queryParameter(Api.FROM_SYMBOL);

                    if (TextUtils.isEmpty(from)) {
                        return null;
                    }

                    Exchange exchange = response.body();
                    if (exchange == null) {
                        return null;
                    }

                    if (ObjectsCompat.equals(oldCountry.code, from)) {
                        int btcStatus = Country.SAME;
                        if (oldCountry.btc != -1) {
                            if (exchange.bitcoin > oldCountry.btc) {
                                btcStatus = Country.RISE;
                            } else if (exchange.bitcoin < oldCountry.btc) {
                                btcStatus = Country.DROP;
                            }
                        }

                        int ethStatus = Country.SAME;
                        if (oldCountry.eth != -1) {
                            if (exchange.bitcoin > oldCountry.btc) {
                                ethStatus = Country.RISE;
                            } else if (exchange.bitcoin < oldCountry.btc) {
                                ethStatus = Country.DROP;
                            }
                        }
                        oldCountry.btcStatus = btcStatus;
                        oldCountry.ethStatus = ethStatus;

                        oldCountry.eth = exchange.ethereum;
                        oldCountry.btc = exchange.bitcoin;
                        oldCountry.refreshedAt = System.currentTimeMillis();
                        return oldCountry;
                    }
                    return null;
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    public static Single<History> loadDailyHistory(Country country, String to) {
        return getApi().getDayHistory(country.code, to)
                .subscribeOn(Schedulers.io())
                .map(response -> {
                    if (response.isSuccessful()) {
                        return response.body();
                    } else {
                        return null;
                    }
                })
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread());
    }

    public static Single<History> loadHourlyHistory(Country country, String to) {
        return getApi().getHourHistory(country.code, to)
                .subscribeOn(Schedulers.io())
                .map(response -> {
                    if (response.isSuccessful()) {
                        return response.body();
                    } else {
                        return null;
                    }
                })
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread());
    }
}