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

import Flutter
import UIKit
import WebKit
import Foundation
import AVFoundation

let WEBVIEW_STORYBOARD = "WebView"
let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController"

public class InAppBrowserManager: NSObject, FlutterPlugin {
    static var registrar: FlutterPluginRegistrar?
    static var channel: FlutterMethodChannel?
    
    // var tmpWindow: UIWindow?
    private var previousStatusBarStyle = -1
    
    public static func register(with registrar: FlutterPluginRegistrar) {
        
    }
    
    init(registrar: FlutterPluginRegistrar) {
        super.init()
        InAppBrowserManager.registrar = registrar
        InAppBrowserManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger())
        registrar.addMethodCallDelegate(self, channel: InAppBrowserManager.channel!)
    }
    
    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let arguments = call.arguments as? NSDictionary

        switch call.method {
            case "openUrl":
                let uuid = arguments!["uuid"] as! String
                let url = arguments!["url"] as! String
                let options = arguments!["options"] as! [String: Any?]
                let headers = arguments!["headers"] as! [String: String]
                let contextMenu = arguments!["contextMenu"] as! [String: Any]
                let windowId = arguments!["windowId"] as? Int64
                let initialUserScripts = arguments!["initialUserScripts"] as? [[String: Any]]
                openUrl(uuid: uuid, url: url, options: options, headers: headers, contextMenu: contextMenu, windowId: windowId, initialUserScripts: initialUserScripts)
                result(true)
                break
            case "openFile":
                let uuid = arguments!["uuid"] as! String
                var url = arguments!["url"] as! String
                let key = InAppBrowserManager.registrar!.lookupKey(forAsset: url)
                let assetURL = Bundle.main.url(forResource: key, withExtension: nil)
                if assetURL == nil {
                    result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url + " asset file cannot be found!", details: nil))
                    return
                } else {
                    url = assetURL!.absoluteString
                }
                let options = arguments!["options"] as! [String: Any?]
                let headers = arguments!["headers"] as! [String: String]
                let contextMenu = arguments!["contextMenu"] as! [String: Any]
                let windowId = arguments!["windowId"] as? Int64
                let initialUserScripts = arguments!["initialUserScripts"] as? [[String: Any]]
                openUrl(uuid: uuid, url: url, options: options, headers: headers, contextMenu: contextMenu, windowId: windowId, initialUserScripts: initialUserScripts)
                result(true)
                break
            case "openData":
                let uuid = arguments!["uuid"] as! String
                let options = arguments!["options"] as! [String: Any?]
                let data = arguments!["data"] as! String
                let mimeType = arguments!["mimeType"] as! String
                let encoding = arguments!["encoding"] as! String
                let baseUrl = arguments!["baseUrl"] as! String
                let contextMenu = arguments!["contextMenu"] as! [String: Any]
                let windowId = arguments!["windowId"] as? Int64
                let initialUserScripts = arguments!["initialUserScripts"] as? [[String: Any]]
                openData(uuid: uuid, options: options, data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl,
                         contextMenu: contextMenu, windowId: windowId, initialUserScripts: initialUserScripts)
                result(true)
                break
            case "openWithSystemBrowser":
                let url = arguments!["url"] as! String
                openWithSystemBrowser(url: url, result: result)
                break
            default:
                result(FlutterMethodNotImplemented)
                break
        }
    }
    
    public func prepareInAppBrowserWebViewController(options: [String: Any?]) -> InAppBrowserWebViewController {
        if self.previousStatusBarStyle == -1 {
            self.previousStatusBarStyle = UIApplication.shared.statusBarStyle.rawValue
        }
        
        let frame: CGRect = UIScreen.main.bounds
        let tmpWindow = UIWindow(frame: frame)
        
        let tmpController = UIViewController()
        let baseWindowLevel = UIApplication.shared.keyWindow?.windowLevel
        tmpWindow.rootViewController = tmpController
        tmpWindow.windowLevel = UIWindow.Level(baseWindowLevel!.rawValue + 1.0)
        tmpWindow.makeKeyAndVisible()
        
        let browserOptions = InAppBrowserOptions()
        let _ = browserOptions.parse(options: options)
        
        let webViewOptions = InAppWebViewOptions()
        let _ = webViewOptions.parse(options: options)
        
        let storyboard = UIStoryboard(name: WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppWebViewFlutterPlugin.self))
        let webViewController = storyboard.instantiateViewController(withIdentifier: WEBVIEW_STORYBOARD_CONTROLLER_ID) as! InAppBrowserWebViewController
        webViewController.tmpWindow = tmpWindow
        webViewController.browserOptions = browserOptions
        webViewController.webViewOptions = webViewOptions
        webViewController.isHidden = browserOptions.hidden
        webViewController.previousStatusBarStyle = previousStatusBarStyle
        webViewController.prepareBeforeViewWillAppear()
        return webViewController
    }
    
    public func openUrl(uuid: String, url: String, options: [String: Any?], headers: [String: String],
                        contextMenu: [String: Any], windowId: Int64?, initialUserScripts: [[String: Any]]?) {
        let absoluteUrl = URL(string: url)!.absoluteURL
        let webViewController = prepareInAppBrowserWebViewController(options: options)
        
        webViewController.uuid = uuid
        webViewController.initURL = absoluteUrl
        webViewController.initHeaders = headers
        webViewController.contextMenu = contextMenu
        webViewController.windowId = windowId
        webViewController.initUserScripts = initialUserScripts ?? []
        
        if webViewController.isHidden {
            webViewController.view.isHidden = true
            webViewController.tmpWindow!.rootViewController!.present(webViewController, animated: false, completion: {() -> Void in

            })
            webViewController.presentingViewController?.dismiss(animated: false, completion: {() -> Void in
                webViewController.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
                UIApplication.shared.delegate?.window??.makeKeyAndVisible()
            })
        }
        else {
            webViewController.tmpWindow!.rootViewController!.present(webViewController, animated: true, completion: {() -> Void in

            })
        }
    }
    
    public func openData(uuid: String, options: [String: Any?], data: String, mimeType: String, encoding: String,
                         baseUrl: String, contextMenu: [String: Any], windowId: Int64?, initialUserScripts: [[String: Any]]?) {
        let webViewController = prepareInAppBrowserWebViewController(options: options)
        
        webViewController.uuid = uuid
        webViewController.initData = data
        webViewController.initMimeType = mimeType
        webViewController.initEncoding = encoding
        webViewController.initBaseUrl = baseUrl
        webViewController.contextMenu = contextMenu
        webViewController.windowId = windowId
        webViewController.initUserScripts = initialUserScripts ?? []
        
        if webViewController.isHidden {
            webViewController.view.isHidden = true
            webViewController.tmpWindow!.rootViewController!.present(webViewController, animated: false, completion: {() -> Void in
                webViewController.webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
            })
            webViewController.presentingViewController?.dismiss(animated: false, completion: {() -> Void in
                webViewController.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
                UIApplication.shared.delegate?.window??.makeKeyAndVisible()
            })
        }
        else {
            webViewController.tmpWindow!.rootViewController!.present(webViewController, animated: true, completion: {() -> Void in
                webViewController.webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
            })
        }
    }
    
    public func openWithSystemBrowser(url: String, result: @escaping FlutterResult) {
        let absoluteUrl = URL(string: url)!.absoluteURL
        if !UIApplication.shared.canOpenURL(absoluteUrl) {
            result(FlutterError(code: "InAppBrowserManager", message: url + " cannot be opened!", details: nil))
            return
        }
        else {
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(absoluteUrl, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: nil)
            } else {
                UIApplication.shared.openURL(absoluteUrl)
            }
        }
        result(true)
    }
}

// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
    return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
