import 'package:flutter/foundation.dart';
import 'package:guru_utils/ads/data/ads_model.dart';
import 'package:guru_utils/log/log.dart';

/// Created by Haoyi on 5/7/21

abstract class AdsLifecycleObserver {
  String get name => "Default";

  void onRequestShow(AdsBundle adsBundle) {}

  void onRequestHide(AdsBundle adsBundle) {}

  void onRequestLoad(AdsBundle adsBundle) {}

  void onRequestDispose(AdsBundle adsBundle) {}

  void onRequestReset(AdsBundle adsBundle) {}

  void onAdLoaded(AdsBundle adsBundle) {}

  void onAdLoadFailed(AdsBundle adsBundle) {}

  void onAdDisplayFailed(AdsBundle adsBundle) {}

  void onAdDisplayed(AdsBundle adsBundle) {}

  void onAdClicked(AdsBundle adsBundle) {}

  void onAdHidden(AdsBundle adsBundle) {}

  // Only Reward Ads
  void onAdRewarded(AdsBundle adsBundle) {}
}

class AdsLifecycleOwner extends AdsLifecycleObserver {
  @override
  String get name => "AdsLifecycleOwner{$observerNames}";

  String get observerNames =>
      adsLifecycleObservers.map((handler) => handler.name).toList().toString();

  final List<AdsLifecycleObserver> adsLifecycleObservers = [];

  void addObserver(AdsLifecycleObserver observer) {
    adsLifecycleObservers.add(observer);
  }

  void removeObserver(AdsLifecycleObserver observer) {
    adsLifecycleObservers.remove(observer);
  }

  @mustCallSuper
  Future dispose() async {
    adsLifecycleObservers.clear();
  }

  @override
  void onRequestShow(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        // Log.w("onRequestShow ${observer.name} ${adsBundle.arguments}");

        observer.onRequestShow(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onRequestShow error:$error", stackTrace: stacktrace, syncFirebase: true);
      }
    }
  }

  @override
  void onRequestHide(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onRequestHide(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onRequestHide error:$error", stackTrace: stacktrace, syncFirebase: true);
      }
    }
  }

  @override
  void onRequestLoad(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onRequestLoad(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onRequestLoad [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }

  @override
  void onRequestDispose(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onRequestDispose(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onRequestDispose [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }

  @override
  void onRequestReset(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onRequestReset(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onRequestReset [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }

  @override
  void onAdLoaded(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onAdLoaded(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onAdLoaded [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }

  @override
  void onAdLoadFailed(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onAdLoadFailed(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onAdLoadFailed [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }

  @override
  void onAdDisplayFailed(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onAdDisplayFailed(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onAdDisplayed [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }

  @override
  void onAdDisplayed(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onAdDisplayed(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onAdDisplayed [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }

  @override
  void onAdClicked(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onAdClicked(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onAdClicked [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }

  @override
  void onAdHidden(AdsBundle adsBundle) {
    Log.w("CompositeAdsHandler onAdHidden !", syncFirebase: true);
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onAdHidden(adsBundle);
      } catch (error, stacktrace) {
        Log.w("onAdHidden [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }

  @override
  void onAdRewarded(AdsBundle adsBundle) {
    for (var observer in adsLifecycleObservers) {
      try {
        observer.onAdRewarded(adsBundle);
      } catch (error, _) {
        Log.w("onAdRewarded [$runtimeType] ERROR!", tag: "Ads", error: error);
      }
    }
  }
}

//
// class CompositeRewardedAdsHandler extends CompositeAdsHandler implements RewardedAdsHandler {
//   String get name => "CompositeRewardedAdsHandler{${super.handlerName}}";
// }
//
typedef AdsCallback = void Function(AdsBundle);

//
class AdsLifecycleObserverDelegate extends AdsLifecycleObserver {
  @override
  final String name;

  final AdsCallback? onRequestShowCallback;

  final AdsCallback? onRequestHideCallback;

  final AdsCallback? onRequestLoadCallback;

  final AdsCallback? onRequestDisposeCallback;

  final AdsCallback? onAdLoadedCallback;

  final AdsCallback? onAdLoadFailedCallback;

  final AdsCallback? onAdDisplayFailedCallback;

  final AdsCallback? onAdDisplayedCallback;

  final AdsCallback? onAdClickedCallback;

  final AdsCallback? onAdHiddenCallback;

  final AdsCallback? onAdRewardedCallback;

  AdsLifecycleObserverDelegate(
      {this.name = "AdsLifecycleObserverDelegate",
      this.onRequestShowCallback,
      this.onRequestHideCallback,
      this.onRequestLoadCallback,
      this.onRequestDisposeCallback,
      this.onAdLoadedCallback,
      this.onAdLoadFailedCallback,
      this.onAdDisplayFailedCallback,
      this.onAdDisplayedCallback,
      this.onAdClickedCallback,
      this.onAdHiddenCallback,
      this.onAdRewardedCallback});

  @override
  void onRequestShow(AdsBundle adsBundle) {
    onRequestShowCallback?.call(adsBundle);
  }

  @override
  void onRequestHide(AdsBundle adsBundle) {
    onRequestHideCallback?.call(adsBundle);
  }

  @override
  void onRequestLoad(AdsBundle adsBundle) {
    onRequestLoadCallback?.call(adsBundle);
  }

  @override
  void onRequestDispose(AdsBundle adsBundle) {
    onRequestDisposeCallback?.call(adsBundle);
  }

  @override
  void onAdLoaded(AdsBundle adsBundle) {
    onAdLoadedCallback?.call(adsBundle);
  }

  @override
  void onAdLoadFailed(AdsBundle adsBundle) {
    onAdLoadFailedCallback?.call(adsBundle);
  }

  @override
  void onAdDisplayFailed(AdsBundle adsBundle) {
    onAdDisplayFailedCallback?.call(adsBundle);
  }

  @override
  void onAdDisplayed(AdsBundle adsBundle) {
    onAdDisplayedCallback?.call(adsBundle);
  }

  @override
  void onAdClicked(AdsBundle adsBundle) {
    onAdClickedCallback?.call(adsBundle);
  }

  @override
  void onAdHidden(AdsBundle adsBundle) {
    onAdHiddenCallback?.call(adsBundle);
  }

  @override
  void onAdRewarded(AdsBundle adsBundle) {
    onAdRewardedCallback?.call(adsBundle);
  }
}
//
// class RewardsAdsHandlerDelegate extends AdsHandlerDelegate implements RewardedAdsHandler {
//   final AdsCallback? onAdRewardedCallback;
//
//   RewardsAdsHandlerDelegate(
//       {String name = "RewardsAdsHandlerDelegate",
//       AdsCallback? onRequestShowCallback,
//       AdsCallback? onRequestHideCallback,
//       AdsCallback? onRequestLoadCallback,
//       AdsCallback? onRequestDisposeCallback,
//       AdsCallback? onAdLoadedCallback,
//       AdsCallback? onAdLoadFailedCallback,
//       AdsCallback? onAdDisplayFailedCallback,
//       AdsCallback? onAdDisplayedCallback,
//       AdsCallback? onAdClickedCallback,
//       AdsCallback? onAdHiddenCallback,
//       this.onAdRewardedCallback})
//       : super(
//             name: name,
//             onRequestShowCallback: onRequestShowCallback,
//             onRequestHideCallback: onRequestHideCallback,
//             onRequestLoadCallback: onRequestLoadCallback,
//             onRequestDisposeCallback: onRequestDisposeCallback,
//             onAdLoadedCallback: onAdLoadedCallback,
//             onAdLoadFailedCallback: onAdLoadFailedCallback,
//             onAdDisplayFailedCallback: onAdDisplayFailedCallback,
//             onAdDisplayedCallback: onAdDisplayedCallback,
//             onAdClickedCallback: onAdClickedCallback,
//             onAdHiddenCallback: onAdHiddenCallback);
//
//   @override
//   void onAdRewarded(AdsBundle adsBundle) {
//     Log.d("[$name]onAdRewarded ${this.onAdRewardedCallback == null}");
//     this.onAdRewardedCallback?.call(adsBundle);
//   }
// }
