import ContentsquareModule

@objc
protocol ExternalBridgeInterface {
    @objc
    func takeSnapshot(parameters: [String: Any])

    @objc
    func enableSessionReplay(parameters: [String: Any])

    @objc
    func updateBridgeConfig(_: Data)

    @objc
    func notifyCSInAppEnabled(parameters: [String: Any])

    @objc
    func shouldHandleWebView(_: AnyObject)

    @objc
    func shouldHandleExternalBridge(_: AnyObject)

    @objc
    func enableUnmaskAll(parameters: [String: Any])

    @objc
    func notifySDKStateChanges(parameters: [String: Any])

    @objc
    func notifySrMaskingVisualisationEnabled(parameters: [String: Any])
}

class ExternalBridgeFactory {
    static func create(
        emitter: _CSEventEmitter.Type
    ) -> ExternalBridgeInterface {
        return ExternalBridgeImpl(
            emitter: emitter
        )
    }
}

private class ExternalBridgeImpl: ExternalBridgeInterface {
    private var _emitter: _CSEventEmitter.Type
    let featureFlagsQueue = DispatchQueue(label: "featureFlagsQueue")

    init(emitter: _CSEventEmitter.Type) {
        _emitter = emitter
    }

    @objc
    func takeSnapshot(parameters: [String: Any]) {
        // no-op
    }

    @objc
    func enableSessionReplay(parameters: [String: Any]) {
        // no-op
    }

    @objc
    func updateBridgeConfig(_ data: Data) {
        guard let serializedConfig = String(data: data, encoding: .utf8) else {
            log(.error, message:"Error while reading the iOS bridge config")
            return
        }

        notifyFeatureFlagsChanged(bridgeConfiguration: serializedConfig)
    }

    @objc
    func notifyCSInAppEnabled(parameters: [String : Any]) {
        // no-op
    }

    @objc
    func shouldHandleWebView(_: AnyObject) {
        // no-op
    }

    @objc
    func shouldHandleExternalBridge(_: AnyObject) {
        // no-op
    }

    @objc
    func enableUnmaskAll(parameters: [String: Any]) {
        // no-op
    }

    @objc
    func notifySDKStateChanges(parameters: [String : Any]) {
        // no-op
    }

    @objc
    func notifySrMaskingVisualisationEnabled(parameters: [String : Any]) {
        // no-op
    }

    private func notifyFeatureFlagsChanged(bridgeConfiguration: String) {
        featureFlagsQueue.async { [self] in
            exponentialBackoff(maxRetries: 10, initialDelay: 0.1, queue: featureFlagsQueue) { completion in
                let completed = self._emitter.shared?.sendFeatureFlags(data: bridgeConfiguration)
                completion(completed ?? false)
            } failure: {
                print("CSLIB ℹ️ Info: All exponential backoff retries failed.")
            }
        }
    }
}

// Expected elements takeSnapshot's parameters dictionary:
enum TakeSnapshotParam: String {
    // path of the rootView of the bridge on the native side. To be used to create TargetViewPaths when generating the snapshot
    case rootPath // as String - mandatory

    // completion block to be used in order to return the json of the generated snapshot asynchronoulsy
    case completion // as (json:String?) -> Void - mandatory
}

enum EnableSessionReplayParam: String {
    // flag, that represents the new status of the session recording.
    case enable // as bool - mandatory
}

enum EnableAPIErrorParam: String {
    // flag, that represents the new status of the API Error.
    case enable // as bool - mandatory
}

enum EnableCrashReporterParam: String {
    // flag, that represents the new status of the crash reporter.
    case enable // as bool - mandatory
}

enum UpdateFeatureFlagsParam: String {
    // list of features flags
    case featureFlags // as [[String: Any]] - mandatory
}

enum NotifyCSInAppEnabledParam: String {
    // flag, that represents the new status of the CSInApp.
    case enable // as bool - mandatory
}

// Expected elements notifySDKStateChanges's parameters dictionary:
enum NotifySDKStateChangesParam: String {

    // The type of action that trigger the state change
    case type // as String - mandatory

    // The different state of the SDK
    case state // as [String: Bool]
}

// Expected elements notifySrMaskingVisualisationEnabled's parameters dictionary:
enum NotifySrMaskingVisualisationEnabledParam: String {
    // flag, that represents the current session replay masking visualisation status
    case enable // as bool - mandatory
}

enum ReactNativeFeaturesKey : String {
    case enableSR = "enableSR"
    case enableApiErrors = "enableApiErrors"
    case enableCrashReporter = "enableCrashReporter"
    case featureFlags = "featureFlags"
    case enableCsInApp = "enableCsInApp"
    case sdkStateChanges = "sdkStateChanges"
}

func registerExternalBridge(interface: ExternalBridgeInterface) {
    Contentsquare.perform(
        NSSelectorFromString("_registerExternalBridgeWithParameters:"),
        with: [
            "interface": interface,
            "type": 2 // reactNative
        ]
    )
}