package com.remax.bill.ads.util

import android.os.Parcel
import com.google.android.gms.ads.BaseAdView
import com.google.android.gms.ads.admanager.AdManagerAdView
import com.google.android.gms.ads.appopen.AppOpenAd
import com.google.android.gms.ads.interstitial.InterstitialAd
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.rewarded.RewardedAd
import com.google.android.gms.ads.AdValue
import com.google.android.gms.common.internal.safeparcel.SafeParcelReader
import com.remax.bill.ads.log.AdLogger
import java.lang.reflect.Field
import kotlin.math.roundToLong

/**
 * AdMob相关的反射工具，统一获取广告的AdValue。
 */
object AdmobReflectionUtil {

    private val ivStackV1 = arrayOf("zzc", "zzj", "zzf", "zzd", "zzae")
    private val ivStackV2 = arrayOf("zzc", "zza", "a", "a", "d", "d", "ae")

    private val bannerStackV1 = arrayOf("zza", "zzj", "zzi", "zze", "zza", "zzk", "zzae")
    private val bannerStackV2 = arrayOf("zza", "zzj", "zza", "a", "a", "f", "a", "e", "ae")

    private val spStackV1 = arrayOf("zzb", "zza", "zzc", "zza", "zzk", "zzae")
    private val spStackV2 = arrayOf("zzb", "zza", "a", "a", "a", "e", "ae")

    private val rvStackV1 = arrayOf("zzb", "zzi", "zze", "zze", "zzae")
    private val rvStackV2 = arrayOf("zzb", "zza", "b", "g", "e", "ae")

    private val nativeStackV1 = arrayOf("zza", "zzb", "zzf", "zzD", "zzb", "zzae")
    private val nativeStackV2 = arrayOf("zza", "zza", "b", "d", "c", "ae")

    /**
     * 通过反射获取任意 AdMob 广告收益信息，当前支持 Banner、开屏、插页、激励、原生。
     * @param ad 广告对象
     * @return [AdValue]，未获取到返回 null
     */
    fun getRevenue(ad: Any?): AdValue? {
        if (ad == null) return null
        val stackList = when (ad) {
            is InterstitialAd -> listOf(ivStackV1, ivStackV2)
            is RewardedAd -> listOf(rvStackV1, rvStackV2)
            is NativeAd -> listOf(nativeStackV1, nativeStackV2)
            is BaseAdView, is AdManagerAdView -> listOf(bannerStackV1, bannerStackV2)
            is AppOpenAd -> listOf(spStackV1, spStackV2)
            else -> emptyList()
        }
        stackList.forEach { stack ->
            val leaf = traverse(ad, stack) ?: return@forEach
            parseLeaf(leaf)?.let { return it }
        }
        AdLogger.w("AdmobReflectionUtil", "未能通过反射解析到收益信息，ad=${ad::class.java.simpleName}")
        return null
    }

    private fun traverse(target: Any, stack: Array<String>): Any? {
        var current: Any? = target
        stack.forEach { fieldName ->
            current = current.getValue(fieldName) ?: return null
        }
        return current
    }

    private fun parseLeaf(leaf: Any): AdValue? {
        if (leaf is AdValue) return leaf
        parcelAdValue(leaf)?.let { return it }

        val fallbackCurrency = leaf.getValue("c")?.toString()?.takeIf { it.isNotBlank() } ?: ""
        val fallbackPrice = leaf.getValue("d")?.toString()?.toDoubleOrNull()
        val fallbackValueMicros = fallbackPrice?.let { (it * 1_000_000.0).roundToLong() } ?: 0L
        return createAdValue(
            precision = AdValue.PrecisionType.UNKNOWN,
            currencyCode = fallbackCurrency,
            valueMicros = fallbackValueMicros
        )
    }

    private fun Any?.getValue(fieldName: String): Any? {
        if (this == null) return null
        return try {
            var clazz: Class<*>? = this::class.java
            var field: Field? = null
            while (clazz != null) {
                try {
                    field = clazz.getDeclaredField(fieldName).apply { isAccessible = true }
                    break
                } catch (ignored: NoSuchFieldException) {
                    clazz = clazz.superclass
                }
            }
            field?.get(this)
        } catch (e: Exception) {
            AdLogger.e("AdmobReflectionUtil", "反射获取字段失败: $fieldName", e)
            null
        }
    }

    private fun parcelAdValue(source: Any?): AdValue? {
        if (source == null) return null
        return try {
            val method = source::class.java.getDeclaredMethod("writeToParcel", Parcel::class.java, Int::class.java)
            method.isAccessible = true
            val parcel = Parcel.obtain()
            try {
                method.invoke(source, parcel, 0)
                parcel.setDataPosition(0)
                val header = SafeParcelReader.validateObjectHeader(parcel)
                var precision = AdValue.PrecisionType.UNKNOWN
                var currency = ""
                var value = 0L
                while (parcel.dataPosition() < header) {
                    val readHeader = SafeParcelReader.readHeader(parcel)
                    when (SafeParcelReader.getFieldId(readHeader)) {
                        2 -> precision = SafeParcelReader.readInt(parcel, readHeader)
                        3 -> currency = SafeParcelReader.createString(parcel, readHeader)
                        4 -> value = SafeParcelReader.readLong(parcel, readHeader)
                        else -> SafeParcelReader.skipUnknownField(parcel, readHeader)
                    }
                }
                SafeParcelReader.ensureAtEnd(parcel, header)
                createAdValue(
                    precision = precision,
                    currencyCode = currency,
                    valueMicros = value
                )
            } finally {
                parcel.recycle()
            }
        } catch (e: Exception) {
            AdLogger.e("AdmobReflectionUtil", "通过Parcel解析AdValue失败", e)
            null
        }
    }

    private fun createAdValue(precision: Int, currencyCode: String, valueMicros: Long): AdValue? {
        return try {
            val constructor = AdValue::class.java.getDeclaredConstructor(
                Int::class.javaPrimitiveType,
                String::class.java,
                Long::class.javaPrimitiveType
            )
            constructor.isAccessible = true
            constructor.newInstance(precision, currencyCode, valueMicros)
        } catch (e: Exception) {
            AdLogger.e("AdmobReflectionUtil", "实例化AdValue失败", e)
            null
        }
    }
}
