package com.reactnativebluestackmodule;

import static com.reactnativebluestackmodule.BluestackModuleViewManager.dpToPx;
import com.reactnativebluestackmodule.common.BluestackAdsCommon;

import android.util.Log;
import android.view.Choreographer;
import android.view.View;
import android.widget.RelativeLayout;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.react.views.view.ReactViewGroup;
import com.mngads.MNGAdsFactory;
import com.mngads.listener.MNGBannerListener;
import com.mngads.listener.MNGClickListener;
import com.mngads.listener.MNGRefreshListener;
import com.mngads.util.MNGFrame;
import com.mngads.util.MNGPreference;

public class BluestackBannerView extends RelativeLayout
        implements LifecycleEventListener, MNGBannerListener, MNGRefreshListener, MNGClickListener {

    private static final String TAG = "BluestackBannerView Bridge";

    private final ReactContext mContext;
    private View myAdView;
    private String mPlacementId;
    private String mPreference;
    private int mWidthDP = -1;
    private int mHeightDP = -1;
    private boolean mShouldLoadNow;
    private boolean mShouldLoadWhenReady;
    private boolean propsChanged;

    private final RCTEventEmitter mEventEmitter;
    private MNGAdsFactory mMNGAdsBannerAdsFactory;

    public BluestackBannerView(ThemedReactContext context) {
        super(context);
        mContext = context;
        mContext.addLifecycleEventListener(this);
        mEventEmitter = mContext.getJSModule(RCTEventEmitter.class);
        // instantiate mng Ads Factory
        mMNGAdsBannerAdsFactory = new MNGAdsFactory(mContext);
    }

    private int getParentId() {
        try {
            return ((View) getParent()).getId();
        } catch (Exception e) {
            return -1;
        }
    }

    public void setPlacementId(String placementId) {
        mPlacementId = placementId;
        Log.d(TAG, "setPlacementId : " + mPlacementId);
    }

    public String getPlacementId() {
        return mPlacementId;
    }

    public void setPreference(String preference) {
        mPreference = preference;
    }

    public String getPreference() {
        return mPreference;
    }

    public void setWidth(int widthDP) {
        mWidthDP = widthDP;
        // Log.d(TAG, "setHeight: mWidthDP: " + mWidthDP);
    }

    public void setHeight(int heightDP) {
        mHeightDP = heightDP;
        // Log.d(TAG, "setHeight: mHeightDP: " + mHeightDP);
    }

    public void setShouldLoadNow(boolean shouldLoadNow) {
        mShouldLoadNow = shouldLoadNow;
    }

    public boolean getShouldLoadNow() {
        return mShouldLoadNow;
    }

    public void setShouldLoadWhenReady(boolean shouldLoadWhenReady) {
        mShouldLoadWhenReady = shouldLoadWhenReady;
    }

    public boolean getShouldLoadWhenReady() {
        return mShouldLoadWhenReady;
    }

    @Override
    public void onHostResume() {

    }

    @Override
    public void onHostPause() {

    }

    @Override
    public void onHostDestroy() {
        Log.d(TAG, "onHostDestroy");
        if (mMNGAdsBannerAdsFactory != null) {
            removeAllViews();
            mMNGAdsBannerAdsFactory.releaseMemory();
            mMNGAdsBannerAdsFactory = null;
            myAdView = null;
        }
    }

    public void createAdViewIfCan() {
        if (myAdView == null &&
                mPlacementId != null &&
                mPreference != null &&
                mWidthDP > -1 &&
                mHeightDP > 0) {
            loadBannerAd(mPreference);
        }
    }

    public void setPropsChanged(boolean propsChanged) {
        this.propsChanged = propsChanged;
    }

    public boolean getPropsChanged() {
        return this.propsChanged;
    }

    public void loadBannerAd(String jsonPreference) {
        // To reset the shouldLoadNow prop value
        mEventEmitter.receiveEvent(getParentId(), Events.EVENT_AD_LOAD_CALLED.toString(), null);

        if (!MNGAdsFactory.isInitialized()) {
            Exception exception = new Exception("SDK is not initialized");
            bannerDidFail(exception);
            return;
        }

        if (mMNGAdsBannerAdsFactory == null || mMNGAdsBannerAdsFactory.isBusy()) {
            Exception exception = new Exception("SDK is busy processing a request");
            bannerDidFail(exception);
            return;
        }

        // set MNG placement Id
        mMNGAdsBannerAdsFactory.setPlacementId(mPlacementId);
        // set MNG listeners
        mMNGAdsBannerAdsFactory.setBannerListener(this);
        mMNGAdsBannerAdsFactory.setRefreshListener(this);
        mMNGAdsBannerAdsFactory.setClickListener(this);

        MNGPreference mMNGPreference = BluestackAdsCommon.getMNGPreference(jsonPreference, mContext);

        // Log.d(TAG, "mMNGAdsBannerAdsFactory.loadBanner");
        if (mMNGPreference != null) {
            mMNGAdsBannerAdsFactory.loadBanner(new MNGFrame(mWidthDP, mHeightDP), mMNGPreference);
        } else {
            mMNGAdsBannerAdsFactory.loadBanner(new MNGFrame(mWidthDP, mHeightDP));
        }

    }

    @Override
    public void bannerDidLoad(View view, int size) {
        Log.d(TAG, "Banner did load preferred Height " + size + "dp");

        removeAllViews();

        myAdView = view;
        mHeightDP = size;
        addView(myAdView);
        setupLayout(this);
        WritableMap event = Arguments.createMap();
        event.putInt("size", size);
        mEventEmitter.receiveEvent(getParentId(), Events.EVENT_LOAD_BANNER.toString(), event);
    }

    private void setupLayout(BluestackBannerView view) {
        Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {
                manuallyLayoutChildren(view);
                view.getViewTreeObserver().dispatchOnGlobalLayout();
                Choreographer.getInstance().postFrameCallback(this);
            }
        });
    }

    public void manuallyLayoutChildren(BluestackBannerView view) {
        // propWidth and propHeight coming from react-native props
        int width = dpToPx(view.getAdWidth(), view.getContext());
        int height = dpToPx(view.getAdHeight(), view.getContext());
        // Log.d(TAG, "Banner manuallyLayoutChildren Height: "
        // + view.getAdHeight() + "dp, " + height + "px");

        view.measure(
                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));

        view.layout(0, 0, width, height);
    }

    @Override
    public void bannerDidFail(Exception e) {
        WritableMap event = Arguments.createMap();
        Log.e(TAG, "Banner did fail : " + e.getMessage() + " error code = " + e.hashCode());
        event.putString("message", e.getMessage());
        event.putInt("code", e.hashCode());
        mEventEmitter.receiveEvent(getParentId(), Events.EVENT_FAIL_TO_LOAD.toString(), event);

        myAdView = null;
        // mHeightDP = 0;
        // setupLayout(this);
    }

    @Override
    public void bannerResize(MNGFrame mngFrame) {

    }

    @Override
    public void onRefreshSucceed() {
        // Log.d(TAG, "on refresh succeed");
        mEventEmitter.receiveEvent(getParentId(), Events.EVENT_REFRESHED_BANNER.toString(), null);
    }

    @Override
    public void onRefreshFailed(Exception e) {
        WritableMap event = Arguments.createMap();
        Log.e(TAG, "on refresh failed : " + e.getMessage() + " error code = " + e.hashCode());
        event.putString("message", e.getMessage());
        event.putInt("code", e.hashCode());
        mEventEmitter.receiveEvent(getParentId(), Events.EVENT_FAIL_TO_REFRESH.toString(), event);
    }

    @Override
    public void onAdClicked() {
        // Log.d(TAG, "on Ad Clicked");
        mEventEmitter.receiveEvent(getParentId(), Events.EVENT_AD_CLICKED.toString(), null);
    }

    public void create(String jsonPreference) {
        // Log.d(TAG, "create banner");
        if (mMNGAdsBannerAdsFactory != null && !mMNGAdsBannerAdsFactory.isBusy()) {
            loadBannerAd(jsonPreference);
        }
    }

    public void destroy() {
        // Log.d(TAG, "destroy banner");
        if (mMNGAdsBannerAdsFactory != null && !mMNGAdsBannerAdsFactory.isBusy()) {
            mMNGAdsBannerAdsFactory.releaseMemory();
        }
    }

    public void refresh(boolean enable) {
        // Log.d(TAG, "refresh enable: " + enable);
        if (mMNGAdsBannerAdsFactory != null && !mMNGAdsBannerAdsFactory.isBusy()) {
            mMNGAdsBannerAdsFactory.toggleRefresh(enable);
        }
    }

    public int getAdWidth() {
        return mWidthDP;
    }

    public int getAdHeight() {
        return mHeightDP;
    }

    public enum Events {
        EVENT_LOAD_BANNER("onAdLoaded"),
        EVENT_FAIL_TO_LOAD("onAdFailedToLoad"),
        EVENT_REFRESHED_BANNER("onAdRefreshed"),
        EVENT_FAIL_TO_REFRESH("onAdFailedToRefresh"),
        EVENT_AD_CLICKED("onAdClicked"),
        EVENT_AD_LOAD_CALLED("onAdLoadCalled");

        private final String mName;

        Events(final String name) {
            mName = name;
        }

        @Override
        public String toString() {
            return mName;
        }
    }
}
