import WebKit;
import ContentsquareModule;

@objc
protocol _WebViewInjector {
    
    func injectWebview(withTag webViewTag:NSNumber,
                       in uiManager:_RCTUIManager)
    func removeInjectionInWebView(withTag webViewTag:NSNumber,
                                  in uiManager:_RCTUIManager)
}

class WebViewInjector {
    
    let viewFinder: _ViewFinder
    let contentsquareType: _Contentsquare.Type
    private var observationToken: NSKeyValueObservation?
    
    @objc
    public init(_ contentsquareType: _Contentsquare.Type = Contentsquare.self,
                viewFinder: _ViewFinder = ViewFinder()) {
        self.viewFinder = viewFinder
        self.contentsquareType = contentsquareType
    }
}

extension WebViewInjector: _WebViewInjector {
    
    @objc
    func injectWebview(withTag webViewTag:NSNumber,
                       in uiManager:_RCTUIManager) {
        viewFinder.findWKWebView(withTag: webViewTag, in: uiManager) { [weak self] webView in
            if let webView = webView, let self = self {
                log(.info, message: "WebView found in native bridge. Ready to be injected")
                // For new CSWebView implementation, we need to wait for the page to be fully loaded before injecting the SDK
                if webView.estimatedProgress == 1.0 {
                    log(.info, message: "Registering webview from native bridge")
                    self.contentsquareType.register(webView: webView)
                } else {
                    log(.info, message: "Adding observer for webview loading completion")
                    self.observationToken = webView.observe(\.isLoading, options: .new, changeHandler: self.observeWebViewLoadingCompletion)
                }
            }
        }
    }
    
    private func observeWebViewLoadingCompletion(webView: WKWebView, change: NSKeyValueObservedChange<Bool>) {
        // This block is only called when `isLoading` changes.
        if !webView.isLoading {
            log(.info, message: "Registering webview from native bridge")
            contentsquareType.register(webView: webView)
            
            // Invalidate the token to stop observing.
            observationToken?.invalidate()
            observationToken = nil
        }
    }
    
    @objc
    func removeInjectionInWebView(withTag webViewTag:NSNumber,
                                  in uiManager:_RCTUIManager) {
        viewFinder.findWKWebView(withTag: webViewTag,
                               in: uiManager) { [weak self] webView in
            if let webView = webView {
                log(.info, message: "WebView found in native bridge. Ready to remove injection")
                self?.contentsquareType.unregister(webView: webView)
            }
        }
    }
}
