//
//  GMWebViewComponent.swift
//  Gengmei
//
//  Created by Terminator on 2017/11/9.
//  Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//

import UIKit
import WebKit
import GMUtil
import GMHud

@objc protocol WKWebViewDelegate: class {
    
    @objc optional func handleLinkTap(_ url: String, host: String?, params: [String: AnyObject]?)
    @objc optional func handleGlobalPageData(_ data: [String: AnyObject])
    /// 数据请求成功h5调起
    @objc optional func globalPageData(_ data: NSDictionary)
    // 机构详情
    @objc optional func globalDataLoaded(_ data: NSDictionary)
    // 导航栏隐藏显示
    @objc optional func controlTitleBarVisible(_ show: Bool)
    @objc optional func diaryDetailControllerShowNotificationAlert()
    /// webView页面点击分享调起(没有share_data包裹)
    @objc optional func webViewShareData(_ data: NSDictionary)
}

///考虑到要做成一个库不想要那么重的继承任务
@objcMembers
class GMWebViewComponent: UIView {
    
    /// 事件
    fileprivate weak var target: AnyObject?
    ///webcomponet
    var webView = WKWebView()
    
    /// 创建一个webiview的配置项
    fileprivate let configuretion = WKWebViewConfiguration()
    fileprivate let userContent = WKUserContentController()
    fileprivate var showInputDic = NSDictionary()
//    var popupView: GMPopUpView!
    
    var moreQueryParams = ""
    var fullUrl = ""
    var path = ""
    
    /// WebView配置项
    var webEngine = GMWebEngine()
    /// 进度条
    fileprivate var progressView: UIProgressView!
    // 弹出键盘view
//    fileprivate var showInputView = WMPostInputView()
    //设置代理
    weak var delegate: WKWebViewDelegate?
    fileprivate var titleObserve: NSKeyValueObservation!
    fileprivate var estimatedProgressObserve: NSKeyValueObservation!
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        configure()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        configure()
    }
    
    fileprivate func configure() {
        
    }
    
    //初始化Preferences
    fileprivate func initPreferences() {
        configuretion.preferences = WKPreferences()
        configuretion.preferences.minimumFontSize = webEngine.minFontSize
        configuretion.preferences.javaScriptEnabled = webEngine.isAutomaticallyJavaScript
    }
    
    /**
     初始化userContent
     同步Ajax Cookie
     */
    fileprivate func initUserContent() {
        userContent.add(self, name: "gmclient")
        let ajaxCookieScript = WKUserScript(source: webEngine.ajaxCookie(), injectionTime: .atDocumentStart, forMainFrameOnly: false)
        userContent.addUserScript(ajaxCookieScript)
        configuretion.userContentController = userContent
        _ = webEngine.scriptMessageHandlerArray.map { [unowned self] (handlerName) in
            self.userContent.add(self, name: handlerName)
        }
    }
    
    func initProgressView() {
        //进度条
        progressView = UIProgressView(progressViewStyle: UIProgressView.Style.bar)
        progressView.progressTintColor = UIColor.mainVisual
        addSubview(progressView)
        progressView.snp.makeConstraints { (make) in
            make.top.left.right.equalTo(0)
            make.height.equalTo(1)
        }
    }
    
    
    fileprivate func initWebView(_ webEngine: GMWebEngine) {
        webView = WKWebView(frame: CGRect.zero, configuration: configuretion)
        webView.uiDelegate = self
        webView.navigationDelegate = self
        if #available(iOS 11.0, *) {
            webView.scrollView.contentInsetAdjustmentBehavior = UIScrollView.ContentInsetAdjustmentBehavior.never
        }
        //开启手势交互
        webView.allowsBackForwardNavigationGestures = webEngine.isAllowsBackForwardGestures
        //滚动条
        webView.scrollView.showsVerticalScrollIndicator = webEngine.isShowScrollIndicator
        webView.scrollView.showsVerticalScrollIndicator = webEngine.isShowScrollIndicator
        webEngine.webView = webView
        addSubview(webView)
        //内容自适应
        webView.snp.makeConstraints { (make) in
            make.left.top.right.bottom.equalTo(0)
        }
    }

    func wrapUrl() -> String {
        if fullUrl.isNonEmpty() {
            return fullUrl.trimSpace()
        } else {
            let apihost = GMServerDomains.apiHost!
            let para = AppDelegate.shareInstance().urlCommonParameters()
            let url = "\(apihost)/hybrid\(path)\(para)\(self.moreQueryParams)"
            return url
        }
    }
    
    ///发送Request
    public func sendRequest() {
        let request = NSMutableURLRequest(url: URL(string: wrapUrl())!)
        request.setValue(webEngine.webCookie(), forHTTPHeaderField: "Cookie")
        webView.load(request as URLRequest)
    }
    
    func webviewLoad(_ target: AnyObject) {
        self.target = target
        initPreferences()
        initUserContent()
        initWebView(webEngine)
        initProgressView()
        addObserver()
        sendRequest()
    }
    
    /// 刷新
    public func reload() {
        //防止 登陆后缓存 修改不同步问题
        let ajaxCookieScript = WKUserScript(source: webEngine.ajaxCookie(), injectionTime: .atDocumentStart, forMainFrameOnly: false)
        self.userContent.addUserScript(ajaxCookieScript)
        webView.reload()
    }
    
    public func loadJsCode(jsCode: String) {
        // 根据JS字符串初始化WKUserScript对象
        self.webView.evaluateJavaScript(jsCode) { (value, error) in
            debugLog(error)
            debugLog(value)
        }

    }
    
    /// 后退
    public func goBack() {
        webView.goBack()
    }
    /// 前进
    public func goForward() {
        webView.goForward()
    }

    /// 移除webView
    public func removeWebView() {
        webView.scrollView.delegate = nil
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: LOGIN_SUCCESS_NOTIFICATION), object: nil)
        titleObserve.invalidate()
        estimatedProgressObserve.invalidate()
        userContent.removeAllUserScripts()
        _ = webEngine.scriptMessageHandlerArray.map { [unowned self] (handlerName) in
            self.userContent.removeScriptMessageHandler(forName: handlerName)
        }
        userContent.removeScriptMessageHandler(forName: "gmclient")
        self.webView.navigationDelegate = nil
        self.webView.uiDelegate = nil
    }

    override func willMove(toSuperview newSuperview: UIView?) {
        if newSuperview == nil {
            removeWebView()
        }
    }

    func addObserver() {
        titleObserve = webView.observe(\.title) { [unowned self] (_, _) in
            guard let controller = self.target as? WMBaseViewController else {
                return
            }
            let title = controller.navigationBar.title ?? ""
            if title == "" {
               controller.navigationBar.title = self.webView.title ?? ""
            }
            
        }

        estimatedProgressObserve = webView.observe(\.estimatedProgress, options: .new) { [unowned self] (_, change) in
            if let currentProgress = change.newValue {
                self.progressView.setProgress(Float(currentProgress), animated: true)
            }
        }
        NotificationCenter.default.addObserver(self, selector: #selector(reload), name: NSNotification.Name(rawValue: LOGIN_SUCCESS_NOTIFICATION), object: nil)
    }
}
// MARK: - WKNavigationDelegate
extension GMWebViewComponent: WKNavigationDelegate {
    
    ///开始发送Request
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        debugLog("didStartProvisionalNavigation")
        GMHudModule.showLoading(nil)
        progressView.isHidden = true;
    }
    
    /**
     Request请求完毕，内容开始返回
     */
    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        GMHudModule.hideLoading()
        debugLog("didCommitNavigation")
    }
    
    /// 页面加载完毕, 不一定及时得到数据
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        webEngine.parseJSPageData { [weak self] (data: [String: AnyObject]) in
            self?.delegate?.handleGlobalPageData?(data)
        }
        // 从H5中取得全局变量
        delay(0.5) {
            self.progressView.isHidden = true
            GMHudModule.hideLoading()
        }
    }
    
    /// URL重定向
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        guard let url = navigationAction.request.url else {
            decisionHandler(.allow)
            return
        }
        let urlHost = url.host ?? ""
        let dict = AppDelegate.navigation.visibleViewController?.getHostDictionary()
        let selector = dict?[urlHost] as? String ?? ""
        if (url.scheme == URL_SCHEME) && (selector.isNonEmpty()) {
            //更美协议
            let urlStr = String(describing: url)
            let encodeUrlScheme = urlStr.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
            let encodeUrl = URL(string: encodeUrlScheme)
            if encodeUrl == nil { return }
            AppDelegate.navigation.visibleViewController?.pushScheme(encodeUrlScheme)
            decisionHandler(.allow)
        } else if url.scheme == URL_HTTP_SCHEME || url.scheme == URL_HTTPS_SCHEME {
            //正常http 请求 或者https请求
            decisionHandler(.allow)
        } else if url.scheme == "tel" {
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            } else {
                UIApplication.shared.openURL(url)
            }
            decisionHandler(.allow)
        } else {
            let urlHost = url.host ?? ""
            if !urlHost.isNonEmpty() {
                decisionHandler(.allow)
            }
            let params = NSString(string: url.absoluteString).urlQueryToDictionary() ?? [:]
            if  self.delegate?.handleLinkTap?(url.absoluteString, host: urlHost, params: params as? [String: AnyObject]) != nil {
                decisionHandler(.cancel)
            } else {
                decisionHandler(.allow)
            }
        }
    }
    //跳转失败的时候调用
    public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        progressView.isHidden = true
        GMHudModule.hideLoading()
        print(error)
    }
    // 内容加载失败时候调用
    public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        progressView.isHidden = true
        GMHudModule.hideLoading()
        print(error)
    }
    
    // 打开新窗口委托
    public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        if navigationAction.targetFrame?.isMainFrame == nil {
            webView.load(navigationAction.request)
        }
        return nil
    }
}

// MARK: - WKUIDelegate 不实现该代理方法 网页内调用弹窗时会抛出异常,导致程序崩溃
extension GMWebViewComponent: WKUIDelegate {
    
    // 获取js 里面的提示
    public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        
        let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in
            completionHandler()
        }))
        alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in
            completionHandler()
        }))
        AppDelegate.visibleController.present(alert, animated: true, completion: nil)
    }
    
    // js 信息的交流
    public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        
        let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in
            completionHandler(true)
        }))
        alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in
            completionHandler(false)
        }))
        AppDelegate.visibleController.present(alert, animated: true, completion: nil)
    }
    
    // 交互。可输入的文本。
    public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        
        let alert = UIAlertController(title: prompt, message: defaultText, preferredStyle: .alert)
        
        alert.addTextField { (textField: UITextField) -> Void in
            textField.textColor = UIColor.red
        }
        alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in
            completionHandler(alert.textFields![0].text!)
        }))
        AppDelegate.visibleController.present(alert, animated: true, completion: nil)
    }
    
    @objc(callPhone:) func callPhone(phone: String) {
        var phoneStr = phone
        if phone.contains("tel") {
            phoneStr = phone.replacingOccurrences(of: "\"", with: "")
        } else {
            phoneStr = "tel:\(phone)"
        }
        if #available(iOS 10.0, *) {
            UIApplication.shared.open(URL(string: phoneStr)!, options: [:], completionHandler: nil)
        } else {
            UIApplication.shared.openURL(URL(string: phoneStr)!)
        }
    }
    
}

// MARK: - WKScriptMessageHandler
extension GMWebViewComponent: WKScriptMessageHandler {
    
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        debugLog(message.body)
        if let dict = message.body as? [String: AnyObject] {
            let method: String = dict["method"] as! String
            let param = dict["param"]
            // 带参数的情况
            if  param != nil {
                let sel = "\(method):"
                if self.responds(to: Selector(sel)) {
                    self.perform(Selector(sel), with: param)
                }
            } else {
                let sel = "\(method)"
                if self.responds(to: Selector(sel)) {
                    self.perform(Selector(sel))
                }
            }
        }
    }
    
    @objc(jsObjShowShareView:) func jsObjShowShareView(with pageData: String) {
        if pageData.isEmpty {
            return
        }
        let data = pageData.data(using: String.Encoding.utf8)
        let dict = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
        self.delegate?.webViewShareData!(dict!)
    }
    
    /// 数据加载完毕, 前端调用方法, 得到pagedata中数据
    @objc(diaryGlobaltLoaded:) func diaryGlobaltLoaded(_ pageData: String) {
        let Data = pageData.data(using: String.Encoding.utf8)
        let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary
        self.delegate?.globalPageData!(dict!)
    }
    
    // 机构详情
    @objc(globalDataLoaded:) func globalDataLoaded(_ pageData: String) {
        let Data = pageData.data(using: String.Encoding.utf8)
        let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary
        self.delegate?.globalDataLoaded!(dict!)
    }
    
    // true:导航栏显示 false:导航栏隐藏
    @objc(controlTitleBarVisible:) func controlTitleBarVisible(_ pageData: String) {
        let Data = pageData.data(using: String.Encoding.utf8)
        let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary
        let show = dict?["show"] as? Bool
        self.delegate?.controlTitleBarVisible!(show ?? false)
    }
    
    // 是否登录:1登录 0未登录
    @objc(isUserLogin) func isUserLogin() -> Int {
        return GMLoginManager.shareInstance().isVisitor ? 0 : 1
    }
    
    @objc(jsPop:) func jsPop(_ isPop: Bool) {
        if isPop {
            DispatchQueue.main.async {
                _ = AppDelegate.navigation.popViewController(animated: true)
            }
        }
    }
    
    @objc(domain) func domain() -> String {
        return GMServerDomains.apiHost
    }
    
    @objc(showLoading) func showLoading() {
        DispatchQueue.main.async {
            AppDelegate.visibleController.showLoading("")
        }
    }
    
    @objc(hideLoading) func hideLoading() {
        DispatchQueue.main.async {
            AppDelegate.visibleController.hideLoading()
        }
    }
    
    @objc(playVideo:) func playVideo(_ JSONString: String) {
        //Alert
        if !JSONString.isNonEmpty() {
            AppDelegate.visibleController.toast("视频无法播放")
            return
        }
        
        let data = JSONString.data(using: String.Encoding.unicode)
        do {
            let dict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! JsonType
            let playFrom = dict["page_name"] as? String ?? ""
            let topicId = dict["topic_id"] as? Int ?? 0
            let businessId = dict["business_id"] as? Int ?? 0
            let cardType = dict["card_type"] as? String ?? ""

            let playBackView = GMPlayerView()
            playBackView.topicId = "\(topicId)"
            playBackView.from = playFrom
            
            // 埋点使用
            let video = GMVideoObject()
            video.businessId = "\(businessId)"
            video.pageName = playFrom
            video.cardType = cardType
            playBackView.video = video
            
            if let playUrl = dict["url"] as? String {
                playBackView.play(playUrl, animationRect: CGRect.zero)
            }
        } catch {
            debugLog("track event error")
        }
    }
    
    /*
    @objc(getAddressBook:) func getAddressBook(_ JSONString: String) {
        DispatchQueue.main.async {
            let manager = GMAddressManager()
            manager.getAddressBookAuthorization()
        }
    }
    
    @objc(chooseOneContactPerson:) func chooseOneContactPerson(_ key: String) {
        let manager = GMAddressManager()
        manager.getOneContactPersonBlock = { result in
            if result != nil {
                if let data = try? JSONSerialization.data(withJSONObject: result!, options: JSONSerialization.WritingOptions.init(rawValue: 0)) {
                    let jsParam = String(data: data, encoding: String.Encoding.utf8)
                    let jsonStr = "gm.util.setContactPerson('\(jsParam ?? "")')" //TODO 待调试
                    self.webView.evaluateJavaScript(jsonStr, completionHandler: nil)
                }
            }
           
        }
        manager.chooseContactPersonAddressBookJsonString()
    }*/
    
    @objc(share:type:) func share(shareDataString: String, type: String) {
//        showAle
    }

    @objc(openBrowser:) func openBrowser(urlStr: String) {
        let alert = UIAlertController.showCustomAlert(withTitle: "提示", message: "你访问的网址将以外部浏览器打开，是否继续？")
        alert.addAction("否", actionHandler: nil)
        alert.addAction("是") {
            if let url = URL(string: urlStr) {
                if #available(iOS 10, *) {
                    UIApplication.shared.open(url, options: [:], completionHandler: nil)
                } else {
                    UIApplication.shared.openURL(url)
                }
            }
        }
    }
    /*
    @objc(jumpToLocationSettings) func jumpToLocationSettings() {
        GMLocationManager.jumpToSettings()
    }
    
    @objc(locationShowAlertIfNotAllowed) func locationShowAlertIfNotAllowed() {
        GMLocationManager.showAlertIfNotAllowed()
    }*/
    
    
    //暂时不写 已经废弃了
    func insurancePurchase(hasBought: Bool) {
        
    }
    
    /*
    @objc(sendMessage:body:) func sendMessage(phone: String, body: String) {
        if GMMessageController.canSendText() {
            let messageVC = GMMessageController()
            messageVC.recipients = [phone]
            messageVC.body = body
            AppDelegate.visibleController.present(messageVC, animated: true, completion: nil)
        } else {
            AppDelegate.navigation.toast("当前设备不支持发短信")
        }
    }*/
    
    @objc(setHeaderHeight:) func setHeaderHeight(height: String) {
        
    }
    
    @objc(setLocalStorage:value:) func setLocalStorage(key: String, value: String) {
        GMCache.storeObject(atDocumentPathWithkey: key, object: value as NSCoding)
    }
    
    @objc(getLocalStorage:) func getLocalStorage(key: String) -> String {
        let cacheValue = GMCache.fetchObject(atDocumentPathWithkey: key) as? String ?? ""
        return cacheValue
    }
    
    @objc(logout) func logout() {
        GMLoginManager.shareInstance().doLogoutAndShowLoginView()
    }
    
    //TODO
    @objc(jsOpenAlbum:isPrivate:) func jsOpenAlbum(_ requestCode: String, isPrivate: Bool) {

    }
    
    // 埋点
    @objc(trackEvent:) func trackEvent(_ JSONString: String) {
        let data = JSONString.data(using: String.Encoding.unicode)
        do {
            let dict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! JsonType
            let params = dict["params"]
            if params is String {
                let objectData = (params as! String).data(using: String.Encoding.unicode)
                let json = try JSONSerialization.jsonObject(with: objectData!, options: .mutableContainers)
                Phobos.track(dict["type"] as? String, attributes: json as! JsonType)
            } else {
                let params = dict["params"] as? JsonType
                if params != nil {
                    Phobos.track(dict["type"] as? String, attributes: params )
                }
            }
        } catch {
            debugLog("track event error")
        }
    }
}
