package com.composition.android.lib.ad.impl

import android.app.Activity
import android.content.Context
import android.view.View
import android.view.ViewGroup
import com.composition.android.lib.ad.AdUnitConfigManager
import com.composition.android.lib.ad.basic.*
import com.composition.android.lib.ad.bean.AdUnitBean
import com.composition.android.lib.ad.factory.AdLoaderFactory
import com.composition.android.lib.ad.interfaces.AdListener
import com.composition.android.lib.ad.interfaces.AdLoader
import com.composition.android.lib.ad.util.adLog
import com.composition.android.lib.ad.util.adLogWithFrame
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

/**
 * @classname:
 * @author: LiuXiaoLong
 * @date: 2022/9/5
 * description:
 */
internal class Api {

    companion object {
        val instance by lazy {
            Api()
        }
    }

    /**
     * 每个广告位最大缓存数量
     */
    private var adSlotMaxCacheCount = 1

    /**
     * 缓存集合
     */
    private var cacheList: MutableList<AdResult.Success> = mutableListOf()

    /**
     * 添加请求成功的广告实例到缓存中
     * @param adResult 请求成功的广告实例
     */
    fun addToCache(adResult: AdResult.Success){
        cacheList.add(adResult)
    }

    /**
     * 预加载广告
     * @param context 上下文
     * @param adSlotNames 要预加载的广告位名称
     */
    suspend fun preloadAd(context: Context, vararg adSlotNames: String) {
        val beans = AdUnitConfigManager.instance.getAdUnitBySlotName(adSlotNames.toList())
        preloadAd(context, beans)
    }

    /**
     * 预加载广告
     * @param context 上下文
     * @param adUnitBeans 要预加载的广告单元配置
     */
    suspend fun preloadAd(context: Context, adUnitBeans: List<AdUnitBean>) {
        val beans = mutableListOf<AdUnitBean>()
        for (adUnitBean in adUnitBeans) {
            if (getAdSlotCacheCount(adUnitBean.adSlotName) < adSlotMaxCacheCount){
                beans.add(adUnitBean)
            }else{
                adLogWithFrame(msg = "广告位:${adUnitBean.adSlotName}已达到最大缓存数量，本次不在进行预加载")
            }
        }

        load(context, adUnitBeans)
            .collect {
                if (it is AdResult.Success) {
                    adLogWithFrame(msg = "预加载广告-${it.adBean.adSlotName}-成功")
                    addToCache(it)
                }else{
                    adLogWithFrame(msg = "预加载广告-${it.adBean.adSlotName}-失败")
                }
            }
    }

    /**
     * 检查是否有缓存的广告
     * @param adSlotName 广告位名称
     */
    fun hasCacheAd(adSlotName: String): Boolean {
        return cacheList.any {
            it.adBean.adSlotName.equals(adSlotName)
        }
    }

    /**
     * 广告位已缓存的实例数量
     */
    private fun getAdSlotCacheCount(adSlotName: String) : Int{
        return cacheList.count {
            it.adBean.adSlotName.equals(adSlotName)
        }
    }

    /**
     * 获取缓存的广告
     *
     */
    fun getCacheAd(adUnitBean: AdUnitBean): AdResult.Success? {
        val ad = cacheList.find {
            it.adBean.equals(adUnitBean)
        }
        if (ad != null) {
            cacheList.remove(ad)
        }
        return ad
    }

    /**
     * 根据广告位名称获取缓存的广告
     */
    fun getCacheAd(adSlotName: String) : AdResult.Success? {
        val ad = cacheList.find {
            it.adBean.adSlotName.equals(adSlotName)
        }
        if (ad != null) {
            cacheList.remove(ad)
        }
        return ad
    }

    /**
     * 根据广告位名称，移除缓存池中对应的广告缓存
     * @param adSlotName 广告位名称
     */
    fun removeCacheAdByAdSlot(adSlotName: String) : Boolean{
        val ad = cacheList.find {
            it.adBean.adSlotName.equals(adSlotName)
        }
        return if (ad != null) {
            return cacheList.remove(ad)
        }else{
            false
        }

    }


    private fun getAdLoader(adUnitBean: AdUnitBean): AdLoader {
        return AdLoaderFactory.getAdLoader(adUnitBean)
    }


    /**
     * 加载广告
     * @param context 上下文
     * @param adUnitBeans 加载的广告单元配置
     */
    fun load(context: Context, adUnitBeans: List<AdUnitBean>): Flow<AdResult> {
        return flow {
            if (adUnitBeans.isNullOrEmpty()) {
                adLogWithFrame(msg = "广告单元配置集合为空")
                emit(AdResult.Fail(adBean = AdUnitBean.emptyAdUnitBean(), msg = "AdUnitBeans 为空"))
                return@flow
            }
            for (adUnitBean in adUnitBeans) {
                adLogWithFrame(msg = "开始加载【${adUnitBean.adSlotName}】广告位【${adUnitBean.adType}】广告")

                if (adUnitBean.loadStrategy.allow().not()) {
                    adLogWithFrame(msg = "广告策略未通过")
                    emit(AdResult.Fail(adUnitBean, AdLoadCode.FAIL, msg = "策略未通过"))
                    continue
                }
                val cacheAd = getCacheAd(adUnitBean)
                if (cacheAd != null) {
                    adLogWithFrame(msg = "从缓存中获取【${adUnitBean.adSlotName}】广告位【${adUnitBean.adType}】广告")
                    emit(cacheAd)
                    continue
                }
                adLogWithFrame(msg = "开始实时加载广告")
                val result = getAdLoader(adUnitBean).load(context, adUnitBean)
                emit(result)
            }
        }
    }


    /**
     * 获取横幅广告View
     * @param context 上下文
     * @param adResult 请求成功的广告实例
     * @param viewHolder 横幅广告的一些配置，可以配置广告的监听
     */
    fun getBannerView(context: Context, adResult: AdResult.Success, viewHolder: BannerAdViewHolder): View? {
        if (adResult.adBean.loadStrategy.allow().not()) {
            return null
        }
        return getAdLoader(adResult.adBean).getBannerView(context, adResult, viewHolder)
    }


    /**
     * 获取原生广告View,包含原生模板广告
     */
    fun getNativeAdView(context: Context, adResult: AdResult.Success, viewHolder: NativeAdViewHolder): View? {
        if (adResult.adBean.loadStrategy.allow().not()) {
            return null
        }
        return getAdLoader(adResult.adBean).getNativeAdView(context, adResult, viewHolder)
    }



    /**
     * 填充原生广告内容
     * 用于外部自己写好了广告布局，然后进行填充操作
     * @param context 上下文
     * @param adResult 请求成功的广告实例
     * @param viewHolder 原生广告布局配置
     * @param advertisersContainerView 广告商的填充视图
     * 例如: Admob原生广告最外层需要 com.google.android.gms.ads.nativead.NativeAdView 进行包裹自定义布局内容 ， advertisersContainerView就传入这个NativeAdView
     *
     * Admob : com.google.android.gms.ads.nativead.NativeAdView
     * GroMore : com.bytedance.msdk.api.format.TTNativeAdView
     * CSJ : 不需要特定的布局， 随意ViewGroup都行
     *
     */
    fun populateNativeAdView(context: Context, adResult: AdResult.Success, viewHolder: NativeAdViewHolder, advertisersContainerView: ViewGroup) {
        getAdLoader(adResult.adBean).populateNativeAdView(context, adResult, viewHolder, advertisersContainerView)
    }

    fun destroyAd(adResult: AdResult?){
        if (adResult != null) {
            getAdLoader(adResult.adBean).destroyAd(adResult)
        }
    }

    /**
     * 显示插屏广告
     */
    fun showInterstitialAd(
        activity: Activity,
        adResult: AdResult.Success,
        adListener: AdListener
    ) {
        if (adResult.adBean.loadStrategy.allow().not()) {
            adListener.onAdShowFail("展示策略未通过")
            return
        }
        getAdLoader(adResult.adBean).showInterstitialAd(activity, adResult, adListener)
    }


    /**
     * 显示激励视频广告
     */
    fun showRewardedAd(
        activity: Activity,
        adResult: AdResult.Success,
        adListener: AdListener
    ) {
        if (adResult.adBean.loadStrategy.allow().not()) {
            adListener.onAdShowFail("展示策略未通过")
            return
        }
        getAdLoader(adResult.adBean).showRewardedAd(activity, adResult, adListener)
    }

    fun showRewardedInterstitialAd(
        activity: Activity,
        adResult: AdResult.Success,
        adListener: AdListener
    ){
        if (adResult.adBean.loadStrategy.allow().not()) {
            adListener.onAdShowFail("展示策略未通过")
            return
        }
        getAdLoader(adResult.adBean).showRewardedInterstitialAd(activity, adResult, adListener)

    }


    /**
     * 显示开屏广告
     */
    fun showSplash(
        activity: Activity,
        splashViewGroup: ViewGroup?,
        success: AdResult.Success,
        adListener: AdListener
    ) {
        if (success.adBean.loadStrategy.allow().not()) {
            adListener.onAdShowFail("展示策略未通过")
            return
        }
        getAdLoader(success.adBean).showSplashAd(activity, splashViewGroup, success, adListener)
    }

    /**
     * 显示全屏广告
     */
    fun showFullScreenAd(
        activity: Activity,
        success: AdResult.Success,
        adListener: AdListener
    ) {
        if (success.adBean.loadStrategy.allow().not()) {
            adListener.onAdShowFail("展示策略未通过")
            return
        }
        getAdLoader(success.adBean).showFullScreenAd(activity, success, adListener)
    }


}