@objc
protocol _CSEventEmitter {
    static var shared: _CSEventEmitter? { get set }
    func addListener(_ eventName: String!)
    func removeListener(_ eventName: String)
    func sendSessionReplayLink(url: String)
    func sendFeatureFlags(data: String) -> Bool
    func isBridgeReady() -> Bool
    func sendMetadataChange(data: Dictionary<String, Any>) -> Bool
}

@objc(CSEventEmitterModule)
class CSEventEmitter: RCTEventEmitter {
    public static var shared: _CSEventEmitter?
    private var listenerCounts: [String: Int] = [:]
    
    enum CSEmitterEvents: String, CaseIterable {
        case onSessionReplayLinkChange = "onSessionReplayLinkChange"
        case getFeatureFlags = "getFeatureFlags"
        case onMetadataChange = "onMetadataChange"
    }
    
    override init() {
        super.init()
        for eventName in CSEmitterEvents.allCases {
            listenerCounts[eventName.rawValue] = 0
        }
        CSEventEmitter.shared = self
    }
    
    override func addListener(_ eventName: String!) {
        super.addListener(eventName)
        if let event = CSEmitterEvents(rawValue: eventName) {
            listenerCounts[event.rawValue, default: 0] += 1
        }
    }
    
    override func supportedEvents() -> [String]! {
        return CSEmitterEvents.allCases.map { $0.rawValue }
    }
    
    func sendEventIfListenersAdded(withName name: String, body: Any) -> Bool {
        guard isBridgeReady() else {
            return false
        }
        
        if hasListeners(eventName: name) {
            sendEvent(withName: name, body: body)
            return true
        }
        return false
    }
    
    internal func hasListeners(eventName: String) -> Bool {
        return (listenerCounts[eventName] ?? 0) > 0
    }
    
    @objc
    public override static func requiresMainQueueSetup() -> Bool {
        return true;
    }
}

extension CSEventEmitter: _CSEventEmitter {
    // This is a custom remove listener method, not to confuse with RN removeListeners method
    public func removeListener(_ eventName: String) {
        if CSEmitterEvents.allCases.map({ $0.rawValue }).contains(eventName) {
            let count = listenerCounts[eventName] ?? 0
            listenerCounts[eventName] = max(0, count - 1)
        }
    }
    
    internal func isBridgeReady() -> Bool {
        return self.bridge != nil
    }
    
    @objc
    public func sendSessionReplayLink(url: String) {
        let _ = sendEventIfListenersAdded(withName: CSEmitterEvents.onSessionReplayLinkChange.rawValue, body: url)
    }
    
    public func sendFeatureFlags(data: String) -> Bool {
        return sendEventIfListenersAdded(withName: CSEmitterEvents.getFeatureFlags.rawValue, body: data)
    }
    
    public func sendMetadataChange(data: Dictionary<String, Any>) -> Bool {
        return sendEventIfListenersAdded(withName: CSEmitterEvents.onMetadataChange.rawValue, body: data)
    }
}
