//
//  ChromeSafariBrowserManager.swift
//  flutter_inappwebview
//
//  Created by Lorenzo Pichilli on 18/12/2019.
//

import Flutter
import UIKit
import WebKit
import Foundation
import AVFoundation
import SafariServices

public class ChromeSafariBrowserManager: ChannelDelegate {
    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser"
    var plugin: SwiftFlutterPlugin?
    var browsers: [String: SafariViewController?] = [:]
    var prewarmingTokens: [String: Any?] = [:]
    
    init(plugin: SwiftFlutterPlugin) {
        super.init(channel: FlutterMethodChannel(name: ChromeSafariBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar.messenger()))
        self.plugin = plugin
    }
    
    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let arguments = call.arguments as? NSDictionary

        switch call.method {
            case "open":
                let id = arguments!["id"] as! String
                let url = arguments!["url"] as! String
                let settings = arguments!["settings"] as! [String: Any?]
                let menuItemList = arguments!["menuItemList"] as! [[String: Any]]
                open(id: id, url: url, settings: settings,  menuItemList: menuItemList, result: result)
                break
            case "isAvailable":
                if #available(iOS 9.0, *) {
                    result(true)
                } else {
                    result(false)
                }
                break
            case "clearWebsiteData":
                if #available(iOS 16.0, *) {
                    SFSafariViewController.DataStore.default.clearWebsiteData {
                        result(true)
                    }
                } else {
                    result(false)
                }
            case "prewarmConnections":
                if #available(iOS 15.0, *) {
                    let stringURLs = arguments!["URLs"] as! [String]
                    var URLs: [URL] = []
                    for stringURL in stringURLs {
                        if let url = URL(string: stringURL) {
                            URLs.append(url)
                        }
                    }
                    let prewarmingToken = SFSafariViewController.prewarmConnections(to: URLs)
                    let prewarmingTokenId = NSUUID().uuidString
                    prewarmingTokens[prewarmingTokenId] = prewarmingToken
                    result([
                        "id": prewarmingTokenId
                    ])
                } else {
                    result(nil)
                }
            case "invalidatePrewarmingToken":
                if #available(iOS 15.0, *) {
                    let prewarmingToken = arguments!["prewarmingToken"] as! [String:Any?]
                    if let prewarmingTokenId = prewarmingToken["id"] as? String,
                       let prewarmingToken = prewarmingTokens[prewarmingTokenId] as? SFSafariViewController.PrewarmingToken? {
                        prewarmingToken?.invalidate()
                        prewarmingTokens[prewarmingTokenId] = nil
                    }
                    result(true)
                } else {
                    result(false)
                }
            default:
                result(FlutterMethodNotImplemented)
                break
        }
    }
    
    public func open(id: String, url: String, settings: [String: Any?], menuItemList: [[String: Any]], result: @escaping FlutterResult) {
        let absoluteUrl = URL(string: url)!.absoluteURL
        
        if #available(iOS 9.0, *), let plugin = plugin {
            
            if let flutterViewController = UIApplication.shared.visibleViewController {
                // flutterViewController could be casted to FlutterViewController if needed
                
                let safariSettings = SafariBrowserSettings()
                let _ = safariSettings.parse(settings: settings)
                
                let safari: SafariViewController
                
                if #available(iOS 11.0, *) {
                    let config = SFSafariViewController.Configuration()
                    safari = SafariViewController(plugin: plugin, id: id, url: absoluteUrl, configuration: config,
                                                  menuItemList: menuItemList, safariSettings: safariSettings)
                } else {
                    // Fallback on earlier versions
                    safari = SafariViewController(plugin: plugin, id: id, url: absoluteUrl, entersReaderIfAvailable: safariSettings.entersReaderIfAvailable,
                                                  menuItemList: menuItemList, safariSettings: safariSettings)
                }
                
                safari.prepareSafariBrowser()
                
                flutterViewController.present(safari, animated: true) {
                    result(true)
                }
                
                browsers[id] = safari
            }
            return
        }
        
        result(FlutterError.init(code: "ChromeSafariBrowserManager", message: "SafariViewController is not available!", details: nil))
    }
    
    public override func dispose() {
        super.dispose()
        let browserValues = browsers.values
        browserValues.forEach { (browser: SafariViewController?) in
            browser?.close(result: nil)
            browser?.dispose()
        }
        browsers.removeAll()
        if #available(iOS 15.0, *) {
            let prewarmingTokensValues = prewarmingTokens.values
            prewarmingTokensValues.forEach { (prewarmingToken: Any?) in
                if let prewarmingToken = prewarmingToken as? SFSafariViewController.PrewarmingToken? {
                    prewarmingToken?.invalidate()
                }
            }
            prewarmingTokens.removeAll()
        }
        plugin = nil
    }
    
    deinit {
        dispose()
    }
}
