package com.anythink.reactnative.splash;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.thinkup.core.api.TUAdInfo;
import com.thinkup.core.api.TUAdSourceStatusListener;
import com.thinkup.core.api.TUNetworkConfirmInfo;
import com.thinkup.core.api.TUAdRequest;
import com.thinkup.core.api.AdError;
import com.anythink.reactnative.event.ATReactNativeEventEmitter;
import com.anythink.reactnative.listener.AdListenerFactory;
import com.anythink.reactnative.utils.BridgeJsonMapUtil;
import com.anythink.reactnative.utils.Const;
import com.anythink.reactnative.utils.MsgTools;
import com.anythink.reactnative.utils.Utils;
import com.thinkup.splashad.api.TUSplashAd;
import com.thinkup.splashad.api.TUSplashAdExtraInfo;
import com.thinkup.splashad.api.TUSplashExListener;

import java.util.HashMap;
import java.util.Map;

/**
* Single placementId screen opening Helper.
* Listener forwards SplashCall via {@link ATReactNativeEventEmitter}; show is rendered into the bridge inner container (highly configurable), and dismiss is removed to prevent leakage.
 */
public class ATSplashHelper {

    private final Context mAppContext;
    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
    private TUSplashAd mSplashAd;
    private String mPlacementId;
    private FrameLayout mContainer;
    private Map<String, Object> mLocalExtra;
    private Map<String, Object> mTkExtra;

    public ATSplashHelper(Context appContext) {
        mAppContext = appContext;
    }

    public void setLocalExtra(Map<String, Object> map) {
        mLocalExtra = map;
        if (mSplashAd != null && map != null) {
            mSplashAd.setLocalExtra(map);
        }
    }

    public void setTKExtra(Map<String, Object> map) {
        mTkExtra = map;
        if (mSplashAd != null && map != null) {
            mSplashAd.setTKExtra(map);
        }
    }

    public Map<String, Object> checkAdStatus() {
        Map<String, Object> map = new HashMap<>(5);
        if (mSplashAd != null) {
            com.thinkup.core.api.TUAdStatusInfo info = mSplashAd.checkAdStatus();
            map.put("isLoading", info.isLoading());
            map.put("isReady", info.isReady());
            TUAdInfo top = info.getTUTopAdInfo();
            if (top != null) {
                map.put("adInfo", top.toString());
            }
            return map;
        }
        map.put("isLoading", false);
        map.put("isReady", false);
        return map;
    }

    public java.util.List<TUAdInfo> validAdCaches() {
        return mSplashAd != null ? mSplashAd.checkValidAdCaches() : null;
    }

    private void emit(String callbackKey, String placementId, TUAdInfo adInfo, String errMsg,
                      Map<String, Object> extra) {
        Map<String, Object> info = null;
        if (adInfo != null) {
            try {
                info = Utils.jsonStrToMap(adInfo.toString());
            } catch (Throwable ignore) {
            }
        }
        ATReactNativeEventEmitter.getInstance().sendCallback(
                Const.CallbackMethodCall.SplashCall, callbackKey, placementId, info, errMsg, extra);
    }

    private void initSplash(final String placementId, final Activity activity, int fetchAdTimeout) {
        mPlacementId = placementId;
        Context ctx = activity != null ? activity : mAppContext;

        TUSplashExListener listener = new TUSplashExListener() {
            @Override
            public void onAdLoaded(boolean isTimeout) {
                MsgTools.printCallback("Splash", "ATSplashHelper", "onAdLoaded",
                        "placementId=" + mPlacementId + "--isTimeout=" + isTimeout);
                Map<String, Object> extra = new HashMap<>();
                extra.put(Const.CallbackKey.isTimeout, isTimeout);
                emit(Const.SplashCallback.LoadedCallbackKey, mPlacementId, null, null, extra);
            }

            @Override
            public void onAdLoadTimeout() {
                MsgTools.printCallback("Splash", "ATSplashHelper", "onAdLoadTimeout",
                        "placementId=" + mPlacementId);
                emit(Const.SplashCallback.TimeoutCallbackKey, mPlacementId, null, null, null);
            }

            @Override
            public void onNoAdError(AdError adError) {
                MsgTools.printCallback("Splash", "ATSplashHelper", "onNoAdError",
                        "placementId=" + mPlacementId + "--error=" + adError.getFullErrorInfo());
                emit(Const.SplashCallback.LoadFailCallbackKey, mPlacementId, null, adError.getFullErrorInfo(), null);
            }

            @Override
            public void onAdShow(TUAdInfo atAdInfo) {
                MsgTools.printCallback("Splash", "ATSplashHelper", "onAdShow",
                        "placementId=" + mPlacementId + "--adInfo=" + atAdInfo);
                emit(Const.SplashCallback.ShowCallbackKey, mPlacementId, atAdInfo, null, null);
            }

            @Override
            public void onAdClick(TUAdInfo atAdInfo) {
                MsgTools.printCallback("Splash", "ATSplashHelper", "onAdClick",
                        "placementId=" + mPlacementId + "--adInfo=" + atAdInfo);
                emit(Const.SplashCallback.ClickCallbackKey, mPlacementId, atAdInfo, null, null);
            }

            @Override
            public void onAdDismiss(TUAdInfo atAdInfo, TUSplashAdExtraInfo atSplashAdExtraInfo) {
                MsgTools.printCallback("Splash", "ATSplashHelper", "onAdDismiss",
                        "placementId=" + mPlacementId + "--adInfo=" + atAdInfo + "--extraInfo=" + atSplashAdExtraInfo);
                emit(Const.SplashCallback.CloseCallbackKey, mPlacementId, atAdInfo, null, null);
                removeContainerOnMain();
            }

            @Override
            public void onDeeplinkCallback(TUAdInfo atAdInfo, boolean isSuccess) {
                MsgTools.printCallback("Splash", "ATSplashHelper", "onDeeplinkCallback",
                        "placementId=" + mPlacementId + "--adInfo=" + atAdInfo + "--isSuccess=" + isSuccess);
                Map<String, Object> extra = new HashMap<>();
                extra.put(Const.CallbackKey.isDeeplinkSuccess, isSuccess);
                emit(Const.SplashCallback.DeeplinkCallbackKey, mPlacementId, atAdInfo, null, extra);
            }

            @Override
            public void onDownloadConfirm(Context context, TUAdInfo atAdInfo, TUNetworkConfirmInfo atNetworkConfirmInfo) {
                MsgTools.printCallback("Splash", "ATSplashHelper", "onDownloadConfirm",
                        "placementId=" + mPlacementId + "--adInfo=" + atAdInfo);
                emit(Const.SplashCallback.DownloadConfirmCallbackKey, mPlacementId, atAdInfo, null, null);
            }
        };

        if (fetchAdTimeout > 0) {
            mSplashAd = new TUSplashAd(ctx, placementId, listener, fetchAdTimeout);
        } else {
            mSplashAd = new TUSplashAd(ctx, placementId, listener);
        }
        if (mLocalExtra != null) {
            mSplashAd.setLocalExtra(mLocalExtra);
        }
        if (mTkExtra != null) {
            mSplashAd.setTKExtra(mTkExtra);
        }

        mSplashAd.setAdRevenueListener(AdListenerFactory.revenueListener());
        mSplashAd.setAdMultipleLoadedListener(AdListenerFactory.multipleLoaded(
                Const.CallbackMethodCall.SplashCall,
                Const.SplashCallback.MultipleLoadedCallbackKey, mPlacementId));
        mSplashAd.setAdDownloadListener(AdListenerFactory.downloadListener());

        mSplashAd.setAdSourceStatusListener(new TUAdSourceStatusListener() {
            @Override
            public void onAdSourceBiddingAttempt(TUAdInfo adInfo) {
                MsgTools.printAdSource("ADSource--Bidding--Attempt", "ATSplashHelper", "onAdSourceBiddingAttempt",
                        MsgTools.adSourceParams(mPlacementId, adInfo));
                emit(Const.SplashCallback.AdSourceBiddingAttemptCallbackKey, mPlacementId, adInfo, null, null);
            }

            @Override
            public void onAdSourceBiddingFilled(TUAdInfo adInfo) {
                MsgTools.printAdSource("ADSource--Bidding--Filled", "ATSplashHelper", "onAdSourceBiddingFilled",
                        MsgTools.adSourceParams(mPlacementId, adInfo));
                emit(Const.SplashCallback.AdSourceBiddingFilledCallbackKey, mPlacementId, adInfo, null, null);
            }

            @Override
            public void onAdSourceBiddingFail(TUAdInfo adInfo, AdError adError) {
                MsgTools.printAdSource("ADSource--Bidding--Fail", "ATSplashHelper", "onAdSourceBiddingFail",
                        MsgTools.adSourceErrorParams(mPlacementId, adInfo, adError));
                emit(Const.SplashCallback.AdSourceBiddingFailCallbackKey, mPlacementId, adInfo,
                        adError != null ? adError.getFullErrorInfo() : null, null);
            }

            @Override
            public void onAdSourceAttempt(TUAdInfo adInfo) {
                MsgTools.printAdSource("ADSource--AD--Start", "ATSplashHelper", "onAdSourceAttempt",
                        MsgTools.adSourceParams(mPlacementId, adInfo));
                emit(Const.SplashCallback.AdSourceAttemptCallbackKey, mPlacementId, adInfo, null, null);
            }

            @Override
            public void onAdSourceLoadFilled(TUAdInfo adInfo) {
                MsgTools.printAdSource("ADSource--AD--Load--Success", "ATSplashHelper", "onAdSourceLoadFilled",
                        MsgTools.adSourceParams(mPlacementId, adInfo));
                emit(Const.SplashCallback.AdSourceLoadFilledCallbackKey, mPlacementId, adInfo, null, null);
            }

            @Override
            public void onAdSourceLoadFail(TUAdInfo adInfo, AdError adError) {
                MsgTools.printAdSource("ADSource--AD--Load--Fail", "ATSplashHelper", "onAdSourceLoadFail",
                        MsgTools.adSourceErrorParams(mPlacementId, adInfo, adError));
                emit(Const.SplashCallback.AdSourceLoadFailCallbackKey, mPlacementId, adInfo,
                        adError != null ? adError.getFullErrorInfo() : null, null);
            }
        });
    }

    public void loadSplash(final String placementId, Map<String, Object> settings, final Activity activity) {
        MsgTools.printMsg("loadSplash: " + placementId);
        if (settings == null) {
            settings = new HashMap<>();
        }
        int fetchAdTimeout = -1;
        try {
            Object t = settings.get("fetchAdTimeout");
            if (t != null) {
                fetchAdTimeout = Integer.parseInt(t.toString());
            }
        } catch (Throwable ignore) {
        }

        if (mSplashAd == null) {
            initSplash(placementId, activity, fetchAdTimeout);
        }
        if (mSplashAd == null) {
            return;
        }

// localExtra is set by setLocalExtra, load only parses atAdRequest
        TUAdRequest atAdRequest = null;
        try {
            atAdRequest = BridgeJsonMapUtil.atAdRequestFromLoadExtraDic(settings);
        } catch (Throwable ignore) {
        }

        if (atAdRequest != null) {
            mSplashAd.loadAd(atAdRequest);
        } else {
            mSplashAd.loadAd();
        }
    }

    /** heightPx>0: container is that pixel height (half screen); else fullscreen. showCustomExt/atCustom via TUShowConfig. Add/show container on main thread. */
    public void show(final Activity activity, final String scenario, final int heightPx,
                     final String showCustomExt, final Object atCustom) {
        MsgTools.printMsg("showSplash: " + mPlacementId + ", heightPx=" + heightPx);
        if (mSplashAd == null) {
            return;
        }
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                removeContainer();
                ViewGroup root = activity.findViewById(android.R.id.content);
                if (root == null) {
                    return;
                }
                FrameLayout container = new FrameLayout(activity);
                int h = heightPx > 0 ? heightPx : ViewGroup.LayoutParams.MATCH_PARENT;
                container.setLayoutParams(new FrameLayout.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT, h));
                root.addView(container);
                mContainer = container;
                boolean useConfig = (showCustomExt != null && showCustomExt.length() > 0) || atCustom != null;
                if (useConfig) {
                    com.thinkup.core.api.TUShowConfig.Builder builder = new com.thinkup.core.api.TUShowConfig.Builder();
                    if (scenario != null && scenario.length() > 0) {
                        builder.scenarioId(scenario);
                    }
                    if (showCustomExt != null && showCustomExt.length() > 0) {
                        builder.showCustomExt(showCustomExt);
                    }
                    BridgeJsonMapUtil.applyAtCustomContentToShowConfigBuilder(builder, atCustom);
                    mSplashAd.show(activity, container, null, builder.build());
                } else if (scenario != null && scenario.length() > 0) {
                    mSplashAd.show(activity, container, scenario);
                } else {
                    mSplashAd.show(activity, container);
                }
            }
        });
    }

    public boolean isAdReady() {
        boolean isReady = mSplashAd != null && mSplashAd.isAdReady();
        MsgTools.printMsg("splash isAdReady: " + mPlacementId + ", " + isReady);
        return isReady;
    }

    private void removeContainerOnMain() {
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                removeContainer();
            }
        });
    }

    /** Main-thread call: remove container from parent layout. */
    private void removeContainer() {
        if (mContainer != null && mContainer.getParent() instanceof ViewGroup) {
            ((ViewGroup) mContainer.getParent()).removeView(mContainer);
        }
        mContainer = null;
    }
}
