import React
import BlazeSDK
import BlazeIMA
import GoogleInteractiveMediaAds
import blaze_rtn_sdk

@objc(RTNBlazeIMA)
class BlazeIMANativeModule: RCTEventEmitter {
    
    override init() {
        super.init()
    }
    
    override static func moduleName() -> String {
        return "RTNBlazeIMA"
    }
    
    @objc override static func requiresMainQueueSetup() -> Bool {
        return true
    }
    
    // This property is now a fallback only
    private let defaultAdditionalQueryParams: [String : String] = [:]
    
    lazy var delegate: BlazeIMADelegate = .init(
        
        onIMAAdError: { [weak self] message in
            self?.onIMAAdError(message)
        },
        
        onIMAAdEvent: { [weak self] params in
            self?.onIMAAdEvent(eventType: params.eventType,
                               adInfo: params.adInfo)
        },
        
        additionalIMATagQueryParams: { [weak self] params in
            return await self?.additionalIMATagQueryParams(params: params) ?? [:]
        },
        
        customIMASettings: { [weak self] params in
            return await self?.customIMASettings(params: params)
        },
        
        overrideAdTagUrl: { [weak self] params in
            return await self?.overrideAdTagUrl(params: params)
        }
        
    )
    
    //------------------- Bridge methods ----------------------//
    
    @objc func enableAds() {
        BlazeIMA.shared.enableAds(delegate: delegate)
    }
    
    @objc func disableAds() {
        BlazeIMA.shared.disableAds()
    }
    
    override func supportedEvents() -> [String] {
        return SupportedAppEvents.allCases.map({ $0.rawValue })
    }

}

extension BlazeRTNIMASettings {
    
    func toImaObject() -> IMASettings {
        let imaSettings = IMASettings()
        
        if let language = language {
            imaSettings.language = language
        }
        
        if let ppid = ppid {
            imaSettings.ppid = ppid
        }
        
        if let sessionId = sessionId {
            imaSettings.sessionID = sessionId
        }
        
        return imaSettings
    }
    
}

extension BlazeIMANativeModule {
    
    func onIMAAdError(_ message: String) {
        let event: BlazeIMAEvent = .init(name: "BlazeIMA.onAdError",
                                         body: [
                                            "errorMessage" : message
                                         ])
        bridge?.sendBlazeIMAEvent(event)
    }
    
    func onIMAAdEvent(eventType: BlazeIMAHandlerEventType,
                      adInfo: BlazeImaAdInfo) {
        let event: BlazeIMAEvent = .init(name: "BlazeIMA.onAdEvent",
                                         body: [
                                            "eventType" : eventType.toReactEventTypeParam
                                         ])
        bridge?.sendBlazeIMAEvent(event)
    }
    
    func additionalIMATagQueryParams(params: BlazeIMADelegate.RequestDataInfo) async -> [String : String] {
        guard let asyncBridge = blazeAsyncBridge else {
            return defaultAdditionalQueryParams
        }
        
        do {
            let result: [String: String] = try await asyncBridge.callJSMethod("BlazeIMA.additionalIMATagQueryParams",
                                                                              params: params.toReactModel)
            return result
        } catch {
            // Log specific error and continue with fallback
            blazeLogDebug("Error additionalIMATagQueryParams: \(error)")
            return self.defaultAdditionalQueryParams
        }
    }
    
    func customIMASettings(params: BlazeIMADelegate.RequestDataInfo) async -> IMASettings? {
        guard let asyncBridge = blazeAsyncBridge else {
            return nil
        }
        
        do {
            let result: BlazeRTNIMASettings? = try await asyncBridge.callJSMethod("BlazeIMA.customIMASettings",
                                                                                  params: params.toReactModel)
            return result?.toImaObject()
        } catch {
            // Log specific error and continue with fallback
            blazeLogDebug("Error customIMASettings: \(error)")
            return nil
        }
    }
    
    func overrideAdTagUrl(params: BlazeIMADelegate.RequestDataInfo) async -> String? {
        guard let asyncBridge = blazeAsyncBridge else {
            return nil
        }
        
        do {
            let result: String? = try await asyncBridge.callJSMethod("BlazeIMA.overrideAdTagUrl",
                                                                     params: params.toReactModel)
            return result
        } catch {
            // Log specific error and continue with fallback
            blazeLogDebug("Error overrideAdTagUrl: \(error)")
            return nil
        }
    }
    
}

extension BlazeIMADelegate.RequestDataInfo {
    
    struct RTNBlazeIMAAdRequestParams: Encodable {
        
        let requestDataInfo: RequestDataInfo
        
        struct RequestDataInfo: Encodable {
            let extraInfo: BlazeRTNContentExtraInfo
        }
        
    }
    
    var toReactModel: RTNBlazeIMAAdRequestParams {
        return .init(requestDataInfo: .init(
            extraInfo: requestDataInfo.extraInfo.toReactModel)
        )
    }
    
}

fileprivate extension BlazeSDK.BlazeIMAHandlerEventType {
    
    var toReactEventTypeParam: String {
        switch self {
            
        case .allAdsCompleted:
            return "allAdsCompleted"
        case .adClicked:
            return "adClicked"
        case .adCompleted:
            return "adCompleted"
        case .adFirstQuartile:
            return "adFirstQuartile"
        case .adLoaded:
            return "adLoaded"
        case .adMidpoint:
            return "adMidpoint"
        case .adPaused:
            return "adPaused"
        case .adResumed:
            return "adResumed"
        case .adSkipped:
            return "adSkipped"
        case .adStarted:
            return "adStarted"
        case .adTapped:
            return "adTapped"
        case .adThirdQuartile:
            return "adThirdQuartile"
        case .adRequested:
            return "adRequested"
        }
    }
    
}
