import Foundation
import BlueStackSDK
import React

@objc(BluestackRewardedAdManager)
class BluestackRewardedAdManager: RCTEventEmitter {
    private static let TAG = "BluestackRewardedAdManager"
    private var rewardedAd: RewardedAd?
    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_REWARD_EARNED = "onRewardEarned"
    private let EVENT_REWARD_TYPE_KEY = "rewardType"
    private let EVENT_REWARD_AMOUNT_KEY = "rewardAmount"

    private let EVENT_KEY = "rewardedEvent"
    private let EVENT_NAME = "RewardedAdEvent"

    override init() {
        isAppActive = true
        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)
    }

    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
    }

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

    override func supportedEvents() -> [String] {
        return [EVENT_NAME]
    }

    @objc override static func requiresMainQueueSetup() -> Bool {
        return true
    }

    override func startObserving() {
//        print("BluestackRewardedAdManager: startObserving")
        hasListeners = true
        flushEvents()
    }

    override func stopObserving() {
//        print("BluestackRewardedAdManager: stopObserving")
        hasListeners = false
    }

    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
        rewardedAd = RewardedAd(placementID: placementId)
        rewardedAd?.delegate = self
        rewardedAd?.fullScreenDelegate = self

        let requestOptions = RNRequestOptions.getRequestOptions(optionsJSON: optionsJSON)

        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
            self.rewardedAd?.load(requestOptions: requestOptions)
        }
    }

    @objc func displayAd() {
        if !showWhenLoaded {
            show()
        } else {
            BlueStackLogger.debug(tag: Self.TAG, message: "Rewarded Ad will be displayed automatically when ad is loaded")
        }
    }

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

    // need to fix this body structure later
    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)
        }
    }

    private func cleanUpAd() {
        rewardedAd = nil
        showWhenLoaded = false
    }
}

extension BluestackRewardedAdManager: RewardedAdDelegate {
    func onAdLoaded(_ ad: BlueStackSDK.RewardedAd) {
        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.RewardedAd, _ 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 onRewardEarned(_ ad: BlueStackSDK.RewardedAd, _ reward: BlueStackSDK.Reward?) {
        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
    //        if let amount = reward?.amount {
    //            print("Reward earned: \(amount.floatValue)")
    //        }
            if let reward = reward {
                self.emitEvent(name: self.EVENT_REWARD_EARNED, body: [
                    self.EVENT_KEY: self.EVENT_REWARD_EARNED,
                    self.EVENT_REWARD_TYPE_KEY: reward.currency ?? "unknown",
                    self.EVENT_REWARD_AMOUNT_KEY: reward.amount ?? 0
                ])
            }
        }
    }
}

extension BluestackRewardedAdManager: 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)
        }
    }
}
