import Foundation
import BlueStackSDK
import React

@objc(BluestackInterstitialAdManager)
class BluestackInterstitialAdManager: RCTEventEmitter {
    private static let TAG = "BluestackInterstitialAdManager"
    private var interstitialAd: InterstitialAd?
    private var hasListeners = false
    private var showWhenLoaded = false
    private var isAppActive = true
    private var eventQueue: [Event] = []

    private struct Event {
        let name: String
        let body: [String: Any]?
    }

    private let EVENT_LOADED_AD = "onAdLoaded"
    private let EVENT_DISAPPEAR_AD = "onAdDismissed"
    private let EVENT_DID_SHOWN_AD = "onAdDisplayed"
    private let EVENT_AD_CLICKED = "onAdClicked"
    private let EVENT_AD_ERROR = "onAdFailedError"
    private let EVENT_AD_MESSAGE_ERROR_KEY = "errorMessage"
    
    private let EVENT_KEY = "interstitialEvent"
    private let EVENT_NAME = "InterstitialAdEvent"

    override init() {
//      print("BluestackInterstitialAdManager init")
        super.init()
        NotificationCenter.default.addObserver(self, selector: #selector(onAppDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(onAppWillResignActive), name: UIApplication.willResignActiveNotification, object: nil)
    }
    
    @objc override static func requiresMainQueueSetup() -> Bool {
        return true
    }

    override static func moduleName() -> String {
        return "BluestackInterstitialAdManager"
    }

    override func supportedEvents() -> [String]! {
        return [EVENT_NAME]
    }
    
    override func startObserving() {
        hasListeners = true
//      print("BluestackInterstitialAdManager: startObserving")
    }
    
    override func stopObserving() {
        hasListeners = false
//      print("BluestackInterstitialAdManager: stopObserving")
    }

    private func tryInitializeSDK(placementId: String, autoDisplay: Bool, preference: String) {
        BluestackManager.sharedInstance?.initializeInternally(placementId: placementId) { [weak self] success, message in
            guard let self = self else { return }
            if success {
                self.loadAd(placementId, autoDisplay: autoDisplay, withPreference: preference)
            } else {
                self.emitEvent(name: self.EVENT_AD_ERROR, body: [
                    self.EVENT_KEY: self.EVENT_AD_ERROR,
                    self.EVENT_AD_MESSAGE_ERROR_KEY: message
                ])
            }
        }
    }

    @objc func loadAd(_ placementId: String, autoDisplay: Bool, withPreference optionsJSON: String) {
        if !MobileAds.sharedInstance().isInitialized() {
            tryInitializeSDK(placementId: placementId, autoDisplay: autoDisplay, preference: optionsJSON)
            return
        }

        cleanUpAd()
        showWhenLoaded = autoDisplay
        interstitialAd = InterstitialAd(placementID: placementId)
        interstitialAd?.delegate = self
        interstitialAd?.fullScreenDelegate = self
        interstitialAd?.viewController = RCTPresentedViewController()

        let requestOptions = RNRequestOptions.getRequestOptions(optionsJSON: optionsJSON)

        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
            self.interstitialAd?.load(requestOptions: requestOptions)
        }
    }
    
    @objc func displayAd() {
        if !showWhenLoaded {
            show()
        } else {
            BlueStackLogger.debug(tag: Self.TAG, message: "Interstitial Ad will be displayed automatically when ad is loaded")
        }
    }

    private func show() {
        if let interstitialAd = interstitialAd {
            if interstitialAd.isReady {
                MainThreadDispatcher.runOnMainThread {
                    interstitialAd.show(fromRootViewController: RCTPresentedViewController())
                }
            } else {
                emitEvent(name: EVENT_AD_ERROR, body: [
                        EVENT_KEY: EVENT_AD_ERROR, 
                        EVENT_AD_MESSAGE_ERROR_KEY: "Interstitial ad is not ready"
                    ])
            }
        } else {
            emitEvent(name: EVENT_AD_ERROR, body: [
                    EVENT_KEY: EVENT_AD_ERROR, 
                    EVENT_AD_MESSAGE_ERROR_KEY: "Interstitial ad is not loaded"
                ])
        }
    }

    private func sendEvent(withBody body: String) {
        if hasListeners {
            sendEvent(withName: EVENT_NAME, body: [EVENT_KEY: body])
        }
    }
    
    private func cleanUpAd() {
        interstitialAd = nil
        showWhenLoaded = false
    }
    
    deinit {
//      print("BluestackInterstitialAdManager deinit")
        NotificationCenter.default.removeObserver(self)
        cleanUpAd()
        eventQueue.removeAll() // Clear the event queue
    }

    @objc private func onAppDidBecomeActive() {
        isAppActive = true
        flushEvents()
    }

    @objc private func onAppWillResignActive() {
        isAppActive = false
    }

    private func emitEvent(name: String, body: [String: Any]? = nil) {
        if isAppActive && hasListeners {
            if(body == nil){
                sendEvent(withName: EVENT_NAME, body: [EVENT_KEY: name])
            }else{
                sendEvent(withName: EVENT_NAME, body: body)
            }
        } else {
            eventQueue.append(Event(name: name, body: body))
        }
    }

    private func flushEvents() {
        guard isAppActive else { return }
        while !eventQueue.isEmpty {
            let event = eventQueue.removeFirst()
            emitEvent(name: event.name, body: event.body)
        }
    }
}

extension BluestackInterstitialAdManager: InterstitialAdDelegate {
    func onAdLoaded(_ ad: BlueStackSDK.InterstitialAd) {
        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
            if self.showWhenLoaded {
                self.show()
            }
            self.emitEvent(name: self.EVENT_LOADED_AD)
        }
    }

    func onAdFailedToLoad(_ ad: BlueStackSDK.InterstitialAd, _ error: any Error) {
        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
            let errorBlueStack = "\(error.localizedDescription), code = \(error._code)"
            self.emitEvent(name: self.EVENT_AD_ERROR, body: [
                self.EVENT_KEY: self.EVENT_AD_ERROR,
                self.EVENT_AD_MESSAGE_ERROR_KEY: errorBlueStack
            ])
            self.cleanUpAd()
        }
    }
}

extension BluestackInterstitialAdManager: FullScreenDelegate {
    func onAdDisplayed(_ ad: any FullScreenDisplayableAd) {
        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
            self.emitEvent(name: self.EVENT_DID_SHOWN_AD)
        }
    }

    func onAdFailedToDisplay(_ ad: any FullScreenDisplayableAd, _ error: any Error) {
        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
            let errorBlueStack = "\(error.localizedDescription), code = \(error._code)"
            self.emitEvent(name: self.EVENT_AD_ERROR, body: [
                self.EVENT_KEY: self.EVENT_AD_ERROR,
                self.EVENT_AD_MESSAGE_ERROR_KEY: errorBlueStack
            ])
            self.cleanUpAd()
        }
    }

    func onAdDismissed(_ ad: any FullScreenDisplayableAd) {
        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
            self.emitEvent(name: self.EVENT_DISAPPEAR_AD)
        }
    }

    func onAdClicked(_ ad: any FullScreenDisplayableAd) {
        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
            self.emitEvent(name: self.EVENT_AD_CLICKED)
        }
    }
}

