package com.reactlibrary;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Toast;

import com.appodeal.ads.Appodeal;
import com.appodeal.ads.BannerCallbacks;
import com.appodeal.ads.InterstitialCallbacks;
import com.appodeal.ads.NativeAd;
import com.appodeal.ads.NativeCallbacks;
import com.appodeal.ads.NonSkippableVideoCallbacks;
import com.appodeal.ads.RewardedVideoCallbacks;
import com.appodeal.ads.UserSettings;
import com.appodeal.ads.native_ad.views.NativeAdViewNewsFeed;
import com.appodeal.ads.utils.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.util.List;

public class AppodealCommonModule extends ReactContextBaseJavaModule implements InterstitialCallbacks, RewardedVideoCallbacks, NonSkippableVideoCallbacks, NativeCallbacks, BannerCallbacks {

    private final ReactApplicationContext reactContext;
    private UserSettings settings;
    private List<NativeAd> nativeAds;

    public AppodealCommonModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        Appodeal.setInterstitialCallbacks(this);
        Appodeal.setRewardedVideoCallbacks(this);
        Appodeal.setNonSkippableVideoCallbacks(this);
        Appodeal.setNativeCallbacks(this);
        Appodeal.setBannerCallbacks(this);
    }

    @Override
    public String getName() {
        return "Appodeal";
    }

    @ReactMethod
    public void showToast(String message) {
        Toast.makeText(getReactApplicationContext(), message, Toast.LENGTH_SHORT).show();
    }

    @ReactMethod
    public void initialize(String appKey, int adTypes, boolean consentValue) {
        Appodeal.setBannerViewId(R.id.appodeal_banner_view);
        Appodeal.initialize(getCurrentActivity(), appKey, adTypes, consentValue);
    }

    @ReactMethod
    public void show(int adTypes, Callback callback){
        boolean result;
        result = Appodeal.show(getCurrentActivity(), adTypes);
        if (callback != null) {
            callback.invoke(result);
        }
    }

    @ReactMethod
    public void onResume(int adTypes){
        Appodeal.onResume(getCurrentActivity(), adTypes);
    }

    @ReactMethod
    public void hide(int adTypes){
        Appodeal.hide(getCurrentActivity(), adTypes);
    }

    @ReactMethod
    public void destroy(int adTypes){
        Appodeal.destroy(adTypes);
    }

    @ReactMethod
    public void set728x90Banners(boolean flag){
        Appodeal.set728x90Banners(flag);
    }

    @ReactMethod
    public void setBannerAnimation(boolean flag){
        Appodeal.setBannerAnimation(flag);
    }

    @ReactMethod
    public void setSmartBanners(boolean flag){
        Appodeal.setSmartBanners(flag);
    }

    @ReactMethod
    public void isLoaded(int adTypes, Callback callback){
        boolean result =  Appodeal.isLoaded(adTypes);
        if (callback != null) {
            callback.invoke(result);
        }
    }

    @ReactMethod
    public void cache(int adTypes, int count){
        if (count > 0) {
            Appodeal.cache(getCurrentActivity(), adTypes, count);
        } else {
            Appodeal.cache(getCurrentActivity(), adTypes);
        }
    }

    @ReactMethod
    public void setAutoCache(int adTypes, boolean isEnabled){
        Appodeal.setAutoCache(adTypes, isEnabled);
    }

    @ReactMethod
    public void setTesting(boolean flag){
        Appodeal.setTesting(flag);
    }

    @ReactMethod
    public void setLogLevel(String level){
        if (level.equals("none"))
            Appodeal.setLogLevel(Log.LogLevel.none);
        else if (level.equals("debug"))
            Appodeal.setLogLevel(Log.LogLevel.debug);
        else if (level.equals("verbose"))
            Appodeal.setLogLevel(Log.LogLevel.verbose);
    }

    private void sendEventToJS(String eventName, WritableMap params) {
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
    }

    @Override
    public void onInterstitialLoaded(boolean isPrecache) {
        WritableMap params = Arguments.createMap();
        params.putBoolean("isPrecache", isPrecache);
        sendEventToJS("onInterstitialLoaded", params);
    }

    @Override
    public void onInterstitialFailedToLoad() {
        sendEventToJS("onInterstitialFailedToLoad", null);
    }

    @Override
    public void onInterstitialShown() {
        sendEventToJS("onInterstitialShown", null);
    }

    @Override
    public void onInterstitialShowFailed() {
        sendEventToJS("onInterstitialShowFailed", null);
    }

    @Override
    public void onInterstitialClicked() {
        sendEventToJS("onInterstitialClicked", null);
    }

    @Override
    public void onInterstitialClosed() {
        sendEventToJS("onInterstitialClosed", null);
    }

    @Override
    public void onInterstitialExpired() {
        sendEventToJS("onInterstitialExpired", null);
    }

    @Override
    public void onRewardedVideoLoaded(boolean b) {
        android.util.Log.v("CALLBACK", "onRewardedVideoLoaded");
        WritableMap params = Arguments.createMap();
        params.putBoolean("isLoaded", b);
        sendEventToJS("onRewardedVideoLoaded", params);
    }

    @Override
    public void onRewardedVideoFailedToLoad() {
        android.util.Log.v("CALLBACK", "onRewardedVideoFailedToLoad");
        sendEventToJS("onRewardedVideoFailedToLoad", null);
    }

    @Override
    public void onRewardedVideoShown() {
        android.util.Log.v("CALLBACK", "onRewardedVideoShown");
        sendEventToJS("onRewardedVideoShown", null);
    }

    @Override
    public void onRewardedVideoShowFailed() {
        android.util.Log.v("CALLBACK", "onRewardedVideoShowFailed");
        sendEventToJS("onRewardedVideoShowFailed", null);
    }

    @Override
    public void onRewardedVideoFinished(double v, String s) {
        android.util.Log.v("CALLBACK", "onRewardedVideoFinished");
        WritableMap params = Arguments.createMap();
        params.putDouble("amount", v);
        params.putString("currency", s);
        sendEventToJS("onRewardedVideoFinished", params);
    }

    @Override
    public void onRewardedVideoClosed(boolean b) {
        android.util.Log.v("CALLBACK", "onRewardedVideoClosed");
        WritableMap params = Arguments.createMap();
        params.putBoolean("isFinished", b);
        sendEventToJS("onRewardedVideoClosed", params);
    }

    @Override
    public void onRewardedVideoExpired() {
        android.util.Log.v("CALLBACK", "onRewardedVideoExpired");
        sendEventToJS("onRewardedVideoExpired", null);
    }

    @Override
    public void onRewardedVideoClicked() {
        android.util.Log.v("CALLBACK", "onRewardedVideoClicked");
        sendEventToJS("onRewardedVideoClicked", null);
    }

    private UserSettings getUserSettings(){
        if(settings == null) {
            settings = Appodeal.getUserSettings(getCurrentActivity());
        }
        return settings;
    }

    @ReactMethod
    public void setAge(int age){
        getUserSettings().setAge(age);
    }

    @ReactMethod
    public void setUserId(String id){
        getUserSettings().setUserId(id);
    }

    @ReactMethod
    public void setGender(String gender){
        if (gender.equals("male"))
            getUserSettings().setGender(com.appodeal.ads.UserSettings.Gender.MALE);
        else if (gender.equals("female"))
            getUserSettings().setGender(com.appodeal.ads.UserSettings.Gender.FEMALE);
        else if (gender.equals("other"))
            getUserSettings().setGender(com.appodeal.ads.UserSettings.Gender.OTHER);
    }

    @ReactMethod
    public void getRewardParameters(ReadableMap args, Callback callback){
        String placement = args.hasKey("placement") ? args.getString("placement") : null;
        WritableMap params = Arguments.createMap();
        if (placement == null) {
            params.putDouble("amount", Appodeal.getRewardParameters().first);
            params.putString("currency", Appodeal.getRewardParameters().second);
        } else {
            params.putDouble("amount", Appodeal.getRewardParameters(placement).first);
            params.putString("currency", Appodeal.getRewardParameters(placement).second);
        }

        if (callback != null) {
            callback.invoke(params);
        }
    }

    @Override
    public void onNonSkippableVideoLoaded(boolean b) {
        android.util.Log.v("CALLBACK", "onRewardedVideoFailedToLoad");
        WritableMap params = Arguments.createMap();
        params.putBoolean("isLoaded", b);
        sendEventToJS("onNonSkippableVideoLoaded", params);
    }

    @Override
    public void onNonSkippableVideoFailedToLoad() {
        android.util.Log.v("CALLBACK", "onRewardedVideoFailedToLoad");
        sendEventToJS("onNonSkippableVideoFailedToLoad", null);
    }

    @Override
    public void onNonSkippableVideoShown() {
        android.util.Log.v("CALLBACK", "onRewardedVideoFailedToLoad");
        sendEventToJS("onNonSkippableVideoFailedToLoad", null);
    }

    @Override
    public void onNonSkippableVideoShowFailed() {
        android.util.Log.v("CALLBACK", "onRewardedVideoFailedToLoad");
        sendEventToJS("onNonSkippableVideoFailedToLoad", null);
    }

    @Override
    public void onNonSkippableVideoFinished() {
        android.util.Log.v("CALLBACK", "onRewardedVideoFailedToLoad");
        sendEventToJS("onNonSkippableVideoFailedToLoad", null);
    }

    @Override
    public void onNonSkippableVideoClosed(boolean b) {
        android.util.Log.v("CALLBACK", "onRewardedVideoFailedToLoad");
        WritableMap params = Arguments.createMap();
        params.putBoolean("isFinished", b);
        sendEventToJS("onNonSkippableVideoClosed", params);
    }

    @Override
    public void onNonSkippableVideoExpired() {
        android.util.Log.v("CALLBACK", "onRewardedVideoFailedToLoad");
        sendEventToJS("onNonSkippableVideoFailedToLoad", null);
    }

    @ReactMethod
    public void getAvailableNativeAdsCount(Callback callback){
        int result = Appodeal.getAvailableNativeAdsCount();
        if (callback != null) {
            callback.invoke(result);
        }
    }

    private List<NativeAd> getNativeAds(int amount){
        if (nativeAds == null || nativeAds.size() < amount) {
            nativeAds = Appodeal.getNativeAds(amount);
        }
        return nativeAds;
    }

    private NativeAd getNativeAd(int amount, int index){
        List<NativeAd> nativeAds = getNativeAds(amount);
        if (nativeAds.size() > index) {
            return nativeAds.get(index);
        } else {
            return nativeAds.get(0);
        }
    }

    @Override
    public void onNativeLoaded() {
        sendEventToJS("onNativeLoaded", null);
    }

    @Override
    public void onNativeFailedToLoad() {
        sendEventToJS("onNativeFailedToLoad", null);
    }

    @Override
    public void onNativeShown(NativeAd nativeAd) {
        WritableMap params = Arguments.createMap();
        params.putString("title", nativeAd.getTitle());
        params.putString("callToAction", nativeAd.getCallToAction());
        params.putString("description", nativeAd.getDescription());
        sendEventToJS("onNativeShown", params);
    }

    @Override
    public void onNativeShowFailed(NativeAd nativeAd) {
        WritableMap params = Arguments.createMap();
        params.putString("title", nativeAd.getTitle());
        params.putString("callToAction", nativeAd.getCallToAction());
        params.putString("description", nativeAd.getDescription());
        sendEventToJS("onNativeShowFailed", params);
    }

    @Override
    public void onNativeClicked(NativeAd nativeAd) {
        WritableMap params = Arguments.createMap();
        params.putString("title", nativeAd.getTitle());
        params.putString("callToAction", nativeAd.getCallToAction());
        params.putString("description", nativeAd.getDescription());
        sendEventToJS("onNativeClicked", params);
    }

    @Override
    public void onNativeExpired() {
        sendEventToJS("onNativeExpired", null);
    }

    @Override
    public void onBannerLoaded(int i, boolean b) {
        WritableMap params = Arguments.createMap();
        params.putInt("height", i);
        params.putBoolean("isPrecache", b);
        sendEventToJS("onBannerLoaded", params);
    }

    @Override
    public void onBannerFailedToLoad() {
        sendEventToJS("onBannerFailedToLoad", null);
    }

    @Override
    public void onBannerShown() {
        sendEventToJS("onBannerShown", null);
    }

    @Override
    public void onBannerShowFailed() {
        sendEventToJS("onBannerShowFailed", null);
    }

    @Override
    public void onBannerClicked() {
        sendEventToJS("onBannerClicked", null);
    }

    @Override
    public void onBannerExpired() {
        sendEventToJS("onBannerExpired", null);
    }
}
