import Foundation
import BlueStackSDK
import React

@objc(BluestackManager)
class BluestackManager: NSObject {
    private static let TAG = "BluestackManager"
    private static let EVENT_INIT_SUCCESS = 1
    private static let EVENT_INIT_FAILED = "SDK_FAILED_TO_INIT"
    private var isInitInProgress = false
    private var isDebugMode = false
    private var isAppActive = false
    private var pendingSdkInitAction: (() -> Void)? = nil

    private var resolveList: [RCTPromiseResolveBlock] = []
    private var rejectList: [RCTPromiseRejectBlock] = []
    private var initCallbacks: [InitializationCallback] = [] // List of internal initialization callbacks
    // private var bridgeObserver: RNBridgeObserver?

    // Static instance for global access
    static var sharedInstance: BluestackManager?
    // InitializationCallback interface
    public typealias InitializationCallback = (_ success: Bool, _ message: String) -> Void

    private let EVENT_NAME = "BluestackManagerEvent"
    override init() {
        isAppActive = true
        super.init()
        BluestackManager.sharedInstance = self
        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 {
        cleanUp()
    }

    @objc private func onAppDidBecomeActive() {
        isAppActive = true
        if let action = pendingSdkInitAction {
            action()
            pendingSdkInitAction = nil
        }
    }

    @objc private func onAppWillResignActive() {
        isAppActive = false
    }
    
    // Required for all React Native modules
    @objc
    static func requiresMainQueueSetup() -> Bool {
        return true
    }
    
    // Explicitly export the module name
    @objc
    static func moduleName() -> String! {
        return "BluestackManager"
    }

    // Export constants that JavaScript can use
    // @objc
    // func constantsToExport() -> [AnyHashable : Any]! {
    //     return [
    //         "EVENT_INIT_SUCCESS": BluestackManager.EVENT_INIT_SUCCESS
    //     ]
    // }
    
    @objc(initializeSDK:withDebugMode:withResolver:withRejecter:)
    func initializeSDK(appId: String, debugMode: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
        resolveList.append(resolve)
        rejectList.append(reject)

        // temporary fix for internal initialization. in next version will expose DebugMode method to react 
        if !isDebugMode {
            isDebugMode = debugMode
        }

        let isAlreadyInitialized = MainThreadDispatcher.runOnMainThreadSync {
            return MobileAds.sharedInstance().isInitialized()
        }

        if isAlreadyInitialized {
            invokeSdkInitCompleteAction(isSuccess: true, message: "BlueStack SDK is already initialized")
            return
        }

        MainThreadDispatcher.runOnMainThread {
            BlueStackLogger.debug(tag: Self.TAG, message: "Initializing BlueStack core with appId: \(appId) and debugMode: \(debugMode)")
            MobileAds.sharedInstance().setDebugMode(enabled: self.isDebugMode)
            MobileAds.sharedInstance().initialize(appID: appId, completion: self.onInitialized)
        }
    }

    func initializeInternally(placementId: String, callback: @escaping InitializationCallback) {
        let appId = placementId.components(separatedBy: "/")[1]
        if MobileAds.sharedInstance().isInitialized() {
            callback(true, "BlueStack is already initialized")
            return
        }

        initCallbacks.append(callback)

        initializeSDK(appId: appId, debugMode: true, resolve: { _ in }, reject: { _, _, _ in })
    }
    
    private func onInitialized(status: InitializationStatus) {

        MainThreadDispatcher.runOnMainThread { [weak self] in
            guard let self = self else { return }
            
            if status.adapterStatuses.isEmpty {
                self.invokeSdkInitCompleteAction(isSuccess: false, message: "No Adapters found")
                return
            }
            
            var isAnyAdapterReady = false
            var errorMessage = "Adapters are not initialized"
            
            let adapterStatusMap = status.adapterStatuses.mapValues { adapterStatus in
                if (adapterStatus.state == .ready) {
                    isAnyAdapterReady = true
                } else if (adapterStatus.name == "mngPerf") {
                    errorMessage = adapterStatus.statusDescription ?? errorMessage
                }
                
                return [
                    "name": adapterStatus.name,
                    "state": adapterStatus.state.rawValue,
                    "description": adapterStatus.statusDescription ?? ""
                ]
            }
            
            if(isDebugMode){
                logAdaptersStatus(adapterStatuses: status.adapterStatuses)
            }
            
            if isAnyAdapterReady {
                self.invokeSdkInitCompleteAction(isSuccess: true, message: "BlueStack is successfully initialized")
            } else {
                self.invokeSdkInitCompleteAction(isSuccess: false, message: errorMessage)
            }
        }
    }
    
    private func logAdaptersStatus(adapterStatuses: [String: AdapterStatus]) {
        BlueStackLogger.debug(tag: Self.TAG, message: "BlueStack Adapters Initialization Status: ")
        adapterStatuses.forEach { (adNetworkName, adapterStatus) in
            BlueStackLogger.debug(tag: Self.TAG, message: " Provider: \(adapterStatus.name), Description: \(adapterStatus.statusDescription ?? ""), State: \(adapterStatus.state)")
        }
    }
    
    private func invokeSdkInitCompleteAction(isSuccess: Bool, message: String) {
        BlueStackLogger.debug(tag: Self.TAG, message: "Invoking SDK init complete action with success: \(isSuccess) and message: \(message)")
        let action = {
            if isSuccess {
                for resolve in self.resolveList {
                    resolve(BluestackManager.EVENT_INIT_SUCCESS)
                }
                for callback in self.initCallbacks {
                    callback(true, "BlueStack is successfully initialized")
                }
            } else {
                for reject in self.rejectList {
                    reject(BluestackManager.EVENT_INIT_FAILED, message, nil)
                }
                for callback in self.initCallbacks {
                    callback(false, message)
                }
            }
            self.cleanUp()
        }

        if isAppActive {
            // Execute the action immediately
            action()
        } else {
            pendingSdkInitAction = action
        }
    }

    private func cleanUp() {
//        isInitInProgress = false
        pendingSdkInitAction = nil
        resolveList.removeAll()
        rejectList.removeAll()
        initCallbacks.removeAll()
    }

    // MARK: - For later use
    @objc func setDebugMode(_ debugMode: Bool) {
        isDebugMode = debugMode
        MainThreadDispatcher.runOnMainThreadSync {
            MobileAds.sharedInstance().setDebugMode(enabled: debugMode)
        }
    }

    func isInDebugMode() -> Bool {
        return isDebugMode
    }

    @objc func isSdkInitialized() -> NSNumber {
        return NSNumber(value: MainThreadDispatcher.runOnMainThreadSync {
            return MobileAds.sharedInstance().isInitialized()
        })
    }
}
