package com.github.material.monitor.demo.helper;

import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.github.material.monitor.AbstractFrameCallback;
import com.github.material.monitor.AdTimingInput;
import com.github.material.monitor.FrameCallback;
import com.github.material.monitor.FrameOptions;
import com.github.material.monitor.FrameRecord;
import com.github.material.monitor.MaterialMonitor;
import com.thinkup.core.api.TUAdInfo;

import java.lang.ref.WeakReference;

/**
 * Demo 侧截帧 / 上报封装（对接文档 §5）。
 *
 * <p>所有 {@link FrameCallback} 回调均在<b>主线程</b>触发（库约定），本类不会切换到其他 Looper。</p>
 *
 * <p>上报完成前库可能强持有 callback；Demo 推荐使用 {@link #demoFrameCallback(Activity)} /
 * {@link #demoFrameCallback(View)}（静态内部类 + {@link WeakReference} 持有 Activity）。
 * 若页面可能在 report 结束前销毁，可在 {@code Activity.onDestroy} 中调用
 * {@link #detachOnDestroy(FrameCallback)}（Demo 一般可省略）。</p>
 */
public final class MaterialMonitorHelper {
    private static final String TAG = "MaterialMonitorHelper";

    private MaterialMonitorHelper() {
    }

    /**
     * 若callback强引用 Activity ,页面销毁时解除 callback 注册，避免 upload 完成前  被间接持有。
     * 须传入与 collect 时相同的 callback 实例。
     */
    public static void detachOnDestroy(FrameCallback callback) {
        if (callback != null) {
            MaterialMonitor.get().detachCallback(callback);
        }
    }

    /** 容器截帧（§5.2），使用 {@link #demoFrameCallback(View)} 作为默认回调 */
    public static void collectFrameFromAdContainer(View view,
                                                   TUAdInfo adInfo,
                                                   AdTimingInput timing,
                                                   long delayMs) {
        collectFrameFromAdContainer(view, adInfo, timing, delayMs, demoFrameCallback(view));
    }

    /**
     * 容器截帧（§5.2）：Banner、开屏、原生视频等。
     * 截帧成功后会自动入队上报，可用 {@link FrameRecord#uploadTaskId} 关联上报回调。
     */
    public static void collectFrameFromAdContainer(View view,
                                                   TUAdInfo adInfo,
                                                   AdTimingInput timing,
                                                   long delayMs,
                                                   FrameCallback callback) {
        MaterialMonitor.get().collectFrameFromAdContainer(view, adInfo, timing,
                new FrameOptions.Builder().delayMs(delayMs).maxSizeKb(300).maxLongEdge(1080).build(),
                callback);
    }

    /** 原生 url-only / 容器截帧（§5.3），使用 {@link #demoFrameCallback(View)} 作为默认回调 */
    public static void collectFrameFromNativeAdContainer(View view,
                                                         TUAdInfo adInfo,
                                                         AdTimingInput timing,
                                                         String creativeAssetUrl,
                                                         long delayMs) {
        collectFrameFromNativeAdContainer(view, adInfo, timing, creativeAssetUrl, delayMs, demoFrameCallback(view));
    }

    /**
     * 原生图片 url-only（§5.3 / §4.4）：有效 http(s) URL 时不截屏，仅上报 meta.image_url；
     * 空白或非法 URL 回退为对 targetView 截屏。
     */
    public static void collectFrameFromNativeAdContainer(View view,
                                                         TUAdInfo adInfo,
                                                         AdTimingInput timing,
                                                         String creativeAssetUrl,
                                                         long delayMs,
                                                         FrameCallback callback) {
        MaterialMonitor.get().collectFrameFromNativeAdContainer(view, adInfo, timing,
                new FrameOptions.Builder().delayMs(delayMs).maxSizeKb(300).maxLongEdge(1080).build(),
                creativeAssetUrl,
                callback);
    }

    /** 非容器截帧（§5.4），使用 {@link #demoFrameCallback(Activity)} 作为默认回调 */
    public static void collectFrameFromAdPage(Activity hostActivity,
                                              TUAdInfo adInfo,
                                              AdTimingInput timing,
                                              long delayMs) {
        collectFrameFromAdPage(hostActivity, adInfo, timing, delayMs, demoFrameCallback(hostActivity));
    }

    /**
     * 非容器截帧（§5.4）：插屏 / 激励等全屏 SDK Activity。
     *
     * @param hostActivity 发起展示的宿主 Activity，延时截帧时用于排除误截宿主页
     */
    public static void collectFrameFromAdPage(Activity hostActivity,
                                              TUAdInfo adInfo,
                                              AdTimingInput timing,
                                              long delayMs,
                                              FrameCallback callback) {
        FrameOptions options = new FrameOptions.Builder().delayMs(delayMs).maxSizeKb(300).maxLongEdge(1080).build();
        MaterialMonitor.get().collectFrameFromAdPage(hostActivity, adInfo, timing, options, callback);
    }

    /**
     * 广告关闭时取消尚未执行的延时截帧（§5.5）。
     * 若广告在 {@link FrameOptions#delayMs} 结束前关闭，应调用以避免截到空白或宿主页。
     */
    public static void onAdClosed(TUAdInfo adInfo) {
        if (adInfo != null) {
            MaterialMonitor.get().onAdClosed(adInfo);
        }
    }

    /**
     * Demo 推荐回调：静态内部类 + {@link WeakReference} 持有 Activity，Toast 用 ApplicationContext。
     */
    public static FrameCallback demoFrameCallback(Activity activity) {
        if (activity == null) {
            return new LeakSafeDemoFrameCallback(null, null);
        }
        return new LeakSafeDemoFrameCallback(activity, activity.getApplicationContext());
    }

    /** 从 View 反查宿主 Activity，用于容器截帧场景的默认回调 */
    public static FrameCallback demoFrameCallback(View anchor) {
        if (anchor == null) {
            return new LeakSafeDemoFrameCallback(null, null);
        }
        Context ctx = anchor.getContext();
        Activity activity = ctx instanceof Activity ? (Activity) ctx : null;
        Context app = ctx != null ? ctx.getApplicationContext() : null;
        return new LeakSafeDemoFrameCallback(activity, app);
    }

    /**
     * 不继承 Activity / View；upload 管线可能持有至终态 report。
     */
    private static final class LeakSafeDemoFrameCallback extends AbstractFrameCallback {
        private final WeakReference<Activity> activityRef;
        private final Context appContext;

        LeakSafeDemoFrameCallback(Activity activity, Context appContext) {
            this.activityRef = activity != null ? new WeakReference<Activity>(activity) : null;
            this.appContext = appContext;
        }

        @Override
        public void onCollectSuccess(FrameRecord record) {
            String style = record != null && record.style != null ? record.style.getFolderName() : "";
            Log.d(TAG, "采集成功 style=" + style + " taskId=" + (record != null ? record.uploadTaskId : "null")
                    + " activityAlive=" + isActivityAlive());
            showToast(style.length() > 0 ? "采集成功: " + style : "采集成功");
        }

        @Override
        public void onCollectFailure(int errorCode, String message, Throwable cause) {
            Log.w(TAG, "采集失败: " + errorCode + " " + message, cause);
            showToast("采集失败: " + errorCode);
        }

        @Override
        public void onReportSuccess(FrameRecord record) {
            Log.d(TAG, "上报成功 taskId=" + (record != null ? record.uploadTaskId : "null")
                    + " activityAlive=" + isActivityAlive());
            showToast("上报成功");
        }

        @Override
        public void onReportSkip(FrameRecord record, String reason) {
            Log.d(TAG, "跳过上报 taskId=" + (record != null ? record.uploadTaskId : "null") + " reason=" + reason);
            showToast("跳过上报: " + (reason != null ? reason : ""));
        }

        @Override
        public void onReportFailure(int errorCode, String message, FrameRecord record, Throwable cause) {
            Log.w(TAG, "上报失败: " + errorCode + " " + message
                    + " taskId=" + (record != null ? record.uploadTaskId : "null"), cause);
            showToast("上报失败: " + errorCode);
        }

        private boolean isActivityAlive() {
            Activity activity = activityRef != null ? activityRef.get() : null;
            return activity != null && !activity.isFinishing();
        }

        private void showToast(String text) {
            if (text == null || appContext == null) {
                return;
            }
            Toast.makeText(appContext, text, Toast.LENGTH_SHORT).show();
        }
    }
}
