// Author: fengshengxiong
// Date: 2024/6/25
// Description: 开屏广告

import 'dart:io' show Platform;

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:tone_snap/data/storage/music_box.dart';
import 'package:tone_snap/modules/launch/launch_controller.dart';
import 'package:tone_snap/utils/log_util.dart';

class AppOpenAdManager {
  AppOpenAdManager._();

  static final AppOpenAdManager _instance = AppOpenAdManager._();

  factory AppOpenAdManager() => _instance;

  /// 加载和显示广告之间允许的最长持续时间
  final Duration maxCacheDuration = const Duration(hours: 4);

  /// 跟踪加载时间，这样我们就不会显示过期的广告
  DateTime? _appOpenLoadTime;

  AppOpenAd? _appOpenAd;
  bool _isShowingAd = false;

  /// 记录关闭时的时间，用于下一次展示时计算时间差
  DateTime? closeDateTime;

  /// 开屏广告单元id
  final adUnitId = Platform.isAndroid
      ? (kReleaseMode ? '' : 'ca-app-pub-3940256099942544/9257395921')
      : (kReleaseMode ? 'ca-app-pub-5684307632319406/2523581084' : 'ca-app-pub-3940256099942544/5575463023');

  /// 加载广告
  Future<void> loadAd() async {
    final List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult.contains(ConnectivityResult.none)) {
      return;
    }
    if (isAdAvailable) {
      return;
    }
    await AppOpenAd.load(
      adUnitId: adUnitId,
      request: const AdRequest(),
      adLoadCallback: AppOpenAdLoadCallback(
        onAdLoaded: (ad) {
          LogUtil.d('开屏广告加载完成');
          _appOpenAd = ad;
          _appOpenLoadTime = DateTime.now();
          if (AppOpenAdManager().isAdAvailable) {
            if (Get.isRegistered<LaunchController>()) {
              LaunchController.to.editChangeValue();
            }
          }
        },
        onAdFailedToLoad: (error) {
          LogUtil.e('开屏广告加载失败: $error');
          // Handle the error.
        },
      ),
    );
  }

  /// 是否可以播放广告
  bool get isAdAvailable {
    return _appOpenAd != null;
  }

  /// 显示广告（如果存在且尚未显示）
  /// 如果先前缓存的广告已过期，则只加载并缓存新广告
  void showAdIfAvailable({Function()? onTap}) {
    if (!isAdAvailable) {
      LogUtil.d('尝试在可用之前显示广告');
      loadAd();
      if(onTap != null) onTap();
      return;
    }
    if (_isShowingAd) {
      LogUtil.d('尝试在已显示广告的情况下显示广告');
      if(onTap != null) onTap();
      return;
    }
    if (DateTime.now().subtract(maxCacheDuration).isAfter(_appOpenLoadTime!)) {
      LogUtil.d('超过了最大缓存持续时间。正在加载另一个广告');
      _appOpenAd!.dispose();
      _appOpenAd = null;
      loadAd();
      if(onTap != null) onTap();
      return;
    }
    if (closeDateTime != null) {
      // 计算时间差
      Duration timeDifference = DateTime.now().difference(closeDateTime!);
      // 获取配置的 openAppEventDuration
      int openAppEventDuration = MusicBox().getOpenAppEventDuration();
      // 检查时间差是否小于10秒
      if (timeDifference < Duration(seconds: openAppEventDuration)) {
        return;
      }
    }
    
    // 设置 fullScreenContentCallback 并显示广告
    _appOpenAd!.fullScreenContentCallback = FullScreenContentCallback(
      // 暂停应用程序中的活动或记录广告展示的时间
      onAdShowedFullScreenContent: (ad) {
        LogUtil.d('$ad onAdShowedFullScreenContent');
        // 隐藏状态栏
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: <SystemUiOverlay>[]);

        _isShowingAd = true;
      },
      // 更适合用于跟踪广告展示的次数和效果，以及执行与广告展示相关的操作
      onAdImpression: (ad) {
        LogUtil.d('$ad onAdImpression');
      },
      onAdFailedToShowFullScreenContent: (ad, error) {
        LogUtil.d('$ad onAdFailedToShowFullScreenContent: $error');
        _isShowingAd = false;
        ad.dispose();
        _appOpenAd = null;

        if(onTap != null) onTap();
      },
      onAdDismissedFullScreenContent: (ad) {
        LogUtil.d('$ad onAdDismissedFullScreenContent');
        closeDateTime = DateTime.now();
        
        // 显示状态栏（用户关闭广告后）
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);

        _isShowingAd = false;
        ad.dispose();
        _appOpenAd = null;
        loadAd();

        if(onTap != null) onTap();
      },
      onAdClicked: (ad) {
        LogUtil.d('$ad onAdClicked');
      },
    );
    _appOpenAd!.show();
  }
}