package com.anythink.reactnative.nativead;

import android.content.Context;

import com.thinkup.core.api.TUAdConst;
import com.anythink.reactnative.utils.MsgTools;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.WeakHashMap;

/**
* Architecture-independent business of Native ViewManager (shared Impl) + 2 commands (updateAssetView / renderNativeAd).
* Both newarch (codegen Interface) and oldarch (@ReactProp + handwritten receiveCommand) shells are forwarded here.
 */
public final class ATNativeAdViewManagerImpl {
    private ATNativeAdViewManagerImpl() {}

    public static final class State {
        public String placementId;
        public String adId;
        public int adWidth;
        public int adHeight;
        public boolean adaptive;
        public boolean attached;
    }

    private static final WeakHashMap<ATNativeContainer, State> STATES = new WeakHashMap<>();

    public static State stateOf(ATNativeContainer v) {
        State s = STATES.get(v);
        if (s == null) {
            s = new State();
            STATES.put(v, s);
        }
        return s;
    }

    public static ATNativeContainer createView(Context ctx) {
        return new ATNativeContainer(ctx);
    }

    public static void onAfterUpdateTransaction(ATNativeContainer view) {
        maybeAttach(view);
    }

    /** Attach only when key props (placementId) are ready; adId may arrive later (setAdId then triggers setContainer/renderIfReady). */
    public static void maybeAttach(ATNativeContainer container) {
        State st = stateOf(container);
        if (st.placementId == null || st.placementId.isEmpty()) {
            return;
        }
        ATNativeManager mgr = ATNativeManager.getInstance();
        ATNativeHelper helper = mgr.getOrCreateHelperForView(st.placementId);
        container.helper = helper;

        if (!st.attached) {
            st.attached = true;
            MsgTools.printMsg("ATNativeAdViewManager attach: " + st.placementId);
// Optional size dp→px
            if (st.adWidth > 0 && st.adHeight > 0) {
                float density = container.getResources().getDisplayMetrics().density;
                Map<String, Object> extra = new HashMap<>();
                extra.put(TUAdConst.KEY.AD_WIDTH, (int) (st.adWidth * density + 0.5f));
                extra.put(TUAdConst.KEY.AD_HEIGHT, (int) (st.adHeight * density + 0.5f));
                helper.setLocalExtra(extra);
            }
        }

// adId When ready, bind the container to the corresponding item + template (express) automatically renders
        if (st.adId != null && !st.adId.isEmpty()) {
            helper.setContainer(st.adId, container);
            helper.renderIfReady(st.adId);
        }
    }

    /** command: updateAssetView(int tag, String name)。
* The name may have the text color suffix "type|c=<int>" parsed on the JS side: remove the clean type and store it in assetTags (both binding paths are compared according to it),
* Colors are saved as assetColors for self-rendering reconstruction */
    public static void updateAssetView(ATNativeContainer view, int assetViewTag, String assetViewName) {
        String type = assetViewName;
        if (assetViewName != null) {
            int sep = assetViewName.indexOf("|c=");
            if (sep >= 0) {
                type = assetViewName.substring(0, sep);
                try {
                    view.assetColors.put(assetViewTag, Integer.parseInt(assetViewName.substring(sep + 3)));
                } catch (NumberFormatException ignore) {
                }
            }
        }
        view.assetTags.put(assetViewTag, type);
        MsgTools.printMsg("updateAssetView: tag=" + assetViewTag + ", type=" + type);
    }

    /** command: renderNativeAd()。 */
    public static void renderNativeAd(ATNativeContainer view) {
        if (view.helper != null) {
            view.helper.renderSelfRender(view.adId, view,
                    new LinkedHashMap<>(view.assetTags), new LinkedHashMap<>(view.assetColors));
        }
    }

    public static void onDrop(final ATNativeContainer view) {
        State st = STATES.remove(view);
// Only destroy this view when adId is bound. Empty adId (cell is dropped before adId prop arrives) is not destroyed——
// Otherwise, helper.destroy("") will fall back to mLastAdId, accidentally killing the most recently displayed ad.
        if (st != null && st.placementId != null && st.adId != null && !st.adId.isEmpty()) {
            MsgTools.printMsg("ATNativeAdViewManager onDropViewInstance -> destroy adId=" + st.adId);
            ATNativeManager.getInstance().destroy(st.placementId, st.adId);
        }
        view.assetTags.clear();
        view.assetColors.clear();
        view.selfRenderActive = false;
        view.helper = null;
        view.adId = null;
// removeAllViews triggers GDT media's TextureView.onSurfaceTextureDestroyed → ExoPlayer to be accessed by the main thread;
// onDrop may be in the Fabric mounting thread, so the main thread is forced to remove the child view to avoid "Player accessed on wrong thread" crash.
        if (android.os.Looper.myLooper() == android.os.Looper.getMainLooper()) {
            view.removeAllViews();
        } else {
            new android.os.Handler(android.os.Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    view.removeAllViews();
                }
            });
        }
    }
}
