//
//  BrowserViewController+WebKitDelegate.swift
//  App
//
//  Created by James Magahern on 2/17/21.
//

import WebKit

extension BrowserViewController: WKNavigationDelegate, WKUIDelegate
{
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        tab.loadError = nil
        
        // Check to make sure we have connected to the web content process
        if !tab.bridge.webContentProcessConnected {
            // This means we started loading a page but the web content process hasn't loaded, which means
            // scripts are not getting blocked.
            
            // If you're ad-hoc signing this, you'll need to disable library validation:
            // sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation DisableLibraryValidation -bool YES
            
            DispatchQueue.main.async { [unowned self] in
                // Stop loading now
                webView.stopLoading()
                
                // Show an alert
                let alert = UIAlertController(title: "Web Process Not Loaded",
                                              message: "The web content process never contacted the host application",
                                              preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
                    alert.dismiss(animated: true, completion: nil)
                }))
                
                present(alert, animated: true, completion: nil)
            }
        }
        
        // Reset tracking this
        tab.allowedScriptOrigins.removeAll()
        tab.blockedScriptOrigins.removeAll()
        updateScriptBlockerButton()
        
        // Blur url bar if applicable
        toolbarController.urlBar.textField.resignFirstResponder()
        
        updateTitleAndURL(forWebView: webView)
        
        if let url = webView.url {
            // Start requesting favicon
            tab.updateFaviconForURL(url)
        }
    }
    
    func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
        // We got rugged!!!!!! Update the favicon again.
        if let url = webView.url {
            // Start requesting favicon
            tab.updateFaviconForURL(url)
        }
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        toolbarController.urlBar.loadProgress = .complete
        
        // Update history
        if let url = webView.url {
            let title = webView.title ?? ""
            BrowserHistory.shared.didNavigate(toURL: url, title: title)
        }
        
        // Publish Tabs
        AttractorServer.shared.publishTabInfo(tabController.tabs.map { $0.tabInfo })
    }
    
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void)
    {
        // Handle command+click
        if (commandKeyHeld || windowButtonHeld) && navigationAction.navigationType == .linkActivated {
            // Cancel navigation in this tab
            decisionHandler(.cancel, preferences)
            
            // Start navigation in a new tab
            createNewTab(withURL: navigationAction.request.url, loadInBackground: self.shiftKeyHeld)
            
            // Reset this flag.
            commandKeyHeld = false
            windowButtonHeld = false
            
            return
        }
        
        var allowJavaScript = tab.javaScriptEnabled
        if !allowJavaScript, let host = navigationAction.request.url?.host {
            // Check origin policy
            allowJavaScript = policyManager.scriptPolicy(forOrigin: host).allowsEmbeddedJavaScript()
        }
        
        preferences.allowsContentJavaScript = allowJavaScript
        
        if let url = navigationAction.request.url,
           let redirectedURL = Settings.shared.redirectRule(for: url)
        {
            tab.beginLoadingURL(redirectedURL)
            decisionHandler(.cancel, preferences)
        } else {
            decisionHandler(.allow, preferences)
        }
    }
    
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        if webView == tab.webView {
            tab.loadError = error
        }
    }
    
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        if webView == tab.webView {
            tab.loadError = error
        }
    }
    
    // MARK: WKUIDelegate
    
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView?
    {
        let newTab = tabController.createNewTab(url: nil, webViewConfiguration: configuration)
        newTab.webView.load(navigationAction.request)
        
        self.tab = newTab
        
        return newTab.webView
    }
    
    func webView(_ webView: WKWebView, contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo, completionHandler: @escaping (UIContextMenuConfiguration?) -> Void) {
        let menuConfig = UIContextMenuConfiguration(identifier: nil,
                                                    previewProvider: nil) { (menuElements: [UIMenuElement]) -> UIMenu? in
            
            let openInNewTab = UIAction(title: "Open in New Tab",
                                        image: UIImage(systemName: "plus.app"),
                                        identifier: nil,
                                        discoverabilityTitle: nil,
                                        attributes: [],
                                        state: .off) { [unowned self] _ in
                self.createNewTab(withURL: elementInfo.linkURL, loadInBackground: false)
            }
            
            let openInBackground = UIAction(title: "Open in Background",
                                        image: UIImage(systemName: "plus.rectangle.on.rectangle"),
                                        identifier: nil,
                                        discoverabilityTitle: nil,
                                        attributes: [],
                                        state: .off) { [unowned self] _ in
                self.createNewTab(withURL: elementInfo.linkURL, loadInBackground: true)
            }
            
            return UIMenu(title: elementInfo.linkURL?.absoluteString ?? "Link",
                          image: nil,
                          identifier: nil,
                          options: .displayInline,
                          children: [ openInNewTab, openInBackground ] + menuElements)
        }
        
        completionHandler(menuConfig)
    }

}
