//
//  SafariViewController.swift
//  flutter_inappwebview
//
//  Created by Lorenzo on 25/09/18.
//

import Foundation
import SafariServices

@available(iOS 9.0, *)
public class SafariViewController: SFSafariViewController, SFSafariViewControllerDelegate, Disposable {
    static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_chromesafaribrowser_"
    var channelDelegate: SafariViewControllerChannelDelegate?
    var safariSettings: SafariBrowserSettings
    var id: String
    var plugin: SwiftFlutterPlugin?
    var menuItemList: [[String: Any]] = []
    
    @available(iOS 11.0, *)
    public init(plugin: SwiftFlutterPlugin, id: String, url: URL, configuration: SFSafariViewController.Configuration, menuItemList: [[String: Any]] = [], safariSettings: SafariBrowserSettings) {
        self.id = id
        self.plugin = plugin
        self.menuItemList = menuItemList
        self.safariSettings = safariSettings
        SafariViewController.prepareConfig(configuration: configuration, safariSettings: safariSettings)
        super.init(url: url, configuration: configuration)
        let channel = FlutterMethodChannel(name: SafariViewController.METHOD_CHANNEL_NAME_PREFIX + id,
                                           binaryMessenger: plugin.registrar.messenger())
        self.channelDelegate = SafariViewControllerChannelDelegate(safariViewController: self, channel: channel)
        self.delegate = self
    }
    
    public init(plugin: SwiftFlutterPlugin, id: String, url: URL, entersReaderIfAvailable: Bool, menuItemList: [[String: Any]] = [], safariSettings: SafariBrowserSettings) {
        self.id = id
        self.plugin = plugin
        self.menuItemList = menuItemList
        self.safariSettings = safariSettings
        super.init(url: url, entersReaderIfAvailable: entersReaderIfAvailable)
        let channel = FlutterMethodChannel(name: SafariViewController.METHOD_CHANNEL_NAME_PREFIX + id,
                                           binaryMessenger: plugin.registrar.messenger())
        self.channelDelegate = SafariViewControllerChannelDelegate(safariViewController: self, channel: channel)
        self.delegate = self
    }
    
    public static func prepareConfig(configuration: SFSafariViewController.Configuration, safariSettings: SafariBrowserSettings) {
        configuration.entersReaderIfAvailable = safariSettings.entersReaderIfAvailable
        configuration.barCollapsingEnabled = safariSettings.barCollapsingEnabled
        if #available(iOS 15.0, *), let activityButtonMap = safariSettings.activityButton {
            configuration.activityButton = .fromMap(map: activityButtonMap)
        }
        if #available(iOS 15.2, *), let eventAttributionMap = safariSettings.eventAttribution {
            configuration.eventAttribution = .fromMap(map: eventAttributionMap)
        }
    }
    
    func prepareSafariBrowser() {
        if #available(iOS 11.0, *) {
            self.dismissButtonStyle = SFSafariViewController.DismissButtonStyle(rawValue: safariSettings.dismissButtonStyle)!
        }
        
        if #available(iOS 10.0, *) {
            if let preferredBarTintColor = safariSettings.preferredBarTintColor, !preferredBarTintColor.isEmpty {
                self.preferredBarTintColor = UIColor(hexString: preferredBarTintColor)
            }
            if let preferredControlTintColor = safariSettings.preferredControlTintColor, !preferredControlTintColor.isEmpty {
                self.preferredControlTintColor = UIColor(hexString: preferredControlTintColor)
            }
        }
        
        self.modalPresentationStyle = UIModalPresentationStyle(rawValue: safariSettings.presentationStyle)!
        self.modalTransitionStyle = UIModalTransitionStyle(rawValue: safariSettings.transitionStyle)!
    }
    
    public override func viewWillAppear(_ animated: Bool) {
        // prepareSafariBrowser()
        super.viewWillAppear(animated)
        channelDelegate?.onOpened()
    }
    
    public override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        channelDelegate?.onClosed()
        self.dispose()
    }
    
    func close(result: FlutterResult?) {
        dismiss(animated: true)
        
        // wait for the animation
        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(400), execute: {() -> Void in
            if let result = result {
               result(true)
            }
        })
    }
    
    public func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
        close(result: nil)
    }
    
    public func safariViewController(_ controller: SFSafariViewController,
                              didCompleteInitialLoad didLoadSuccessfully: Bool) {
        channelDelegate?.onCompletedInitialLoad(didLoadSuccessfully: didLoadSuccessfully)
    }
    
    public func safariViewController(_ controller: SFSafariViewController, activityItemsFor URL: URL, title: String?) -> [UIActivity] {
        guard let plugin = plugin else {
            return []
        }
        var uiActivities: [UIActivity] = []
        menuItemList.forEach { (menuItem) in
            let activity = CustomUIActivity(plugin: plugin, viewId: id, id: menuItem["id"] as! Int64, url: URL,
                                            title: title, label: menuItem["label"] as? String, type: nil,
                                            image: .fromMap(map: menuItem["image"] as? [String:Any?]))
            uiActivities.append(activity)
        }
        return uiActivities
    }

    public func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo url: URL) {
        channelDelegate?.onInitialLoadDidRedirect(url: url)
    }
    
    public func safariViewControllerWillOpenInBrowser(_ controller: SFSafariViewController) {
        channelDelegate?.onWillOpenInBrowser()
    }
    
    public func dispose() {
        channelDelegate?.dispose()
        channelDelegate = nil
        delegate = nil
        plugin?.chromeSafariBrowserManager?.browsers[id] = nil
        plugin = nil
    }
    
    deinit {
        debugPrint("SafariViewController - dealloc")
        dispose()
    }
}
