//
//  ThirdTabViewController.swift
//  AppBuilder
//
//  Created by Kevin Maulana on 30/03/22.
//

import UIKit
import WebKit
import NexilisLite
import Speech

class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate, WKNavigationDelegate, WKScriptMessageHandler  {

    @IBOutlet weak var webView: WKWebView!
    var address = ""
    private var lastContentOffset: CGFloat = 0
    
    var isAllowSpeech = false
    
    var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en"))

    var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
    var recognitionTask : SFSpeechRecognitionTask?
    let audioEngine = AVAudioEngine()
    var alertController = UIAlertController()
    
    var dateRefresh: Date?
    public static var forceRefresh = false
    public static var inView = false
    public static var atFirstPage = true
    public static var showModal = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
        tapGesture.cancelsTouchesInView = false
        tapGesture.delegate = self
        webView.scrollView.addGestureRecognizer(tapGesture)
        let refreshControl = UIRefreshControl()
        refreshControl.addTarget(self, action: #selector(reloadWebView(_:)), for: .valueChanged)
        webView.scrollView.addSubview(refreshControl)
        webView.scrollView.delegate = self
        webView.navigationDelegate = self
        webView.allowsBackForwardNavigationGestures = true
        
        let contentController = self.webView.configuration.userContentController
        contentController.add(self, name: "checkProfile")
        contentController.add(self, name: "setIsProductModalOpen")
        contentController.add(self, name: "toggleVoiceSearch")
        contentController.add(self, name: "blockUser")
        contentController.add(self, name: "showAlert")
        contentController.add(self, name: "closeProfile")
        contentController.add(self, name: "tabShowHide")
        
        let source: String = "var meta = document.createElement('meta');" +
            "meta.name = 'viewport';" +
            "meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';" +
            "var head = document.getElementsByTagName('head')[0];" +
            "head.appendChild(meta);" +
        "$('#header-layout').find('.col-8').removeClass('col-8').addClass('col');" +
        "$('#header-layout').find('.col-4').removeClass('col-4').addClass('col');"
        let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
        contentController.addUserScript(script)
        NotificationCenter.default.addObserver(self, selector: #selector(onShowAC(notification:)), name: NSNotification.Name(rawValue: "onShowAC"), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(onRefreshWebView(notification:)), name: NSNotification.Name(rawValue: "onRefreshWebView"), object: nil)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        if ThirdTabViewController.inView {
           return
        }
        ThirdTabViewController.inView = true
        let me = UserDefaults.standard.string(forKey: "me")
        
        var myURL : URL?
        let lang = UserDefaults.standard.string(forKey: "i18n_language")
        var intLang = 0
        if lang == "id" {
            speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "id"))
            intLang = 1
        }
        switch(ViewController.tab3){
        case "0":
            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
            myURL = URL(string: address)
        case "1":
            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
            myURL = URL(string: address)
        case "2":
            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)"
            myURL = URL(string: address)
        case "3":
            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)"
            myURL = URL(string: address)
        case "4":
            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)"
            myURL = URL(string: address)
        default:
            if(!ViewController.tab3.isEmpty){
                if(ViewController.tab3.lowercased().contains("https://") || ViewController.sURL.lowercased().contains("http://")){
                    address = ViewController.tab3
                    myURL = URL(string: address)
                }
                else {
                    address = "https://\(ViewController.tab3)"
                    myURL = URL(string: address)
                }
            }
        }
        print(address)
        if let u = myURL{
            self.webView.evaluateJavaScript("{window.localStorage.setItem('currentTab','\(ViewController.tab3)')}")
            if ((dateRefresh == nil || Int(Date().timeIntervalSince(dateRefresh!)) >= 60) && ThirdTabViewController.atFirstPage) || ThirdTabViewController.forceRefresh {
                let myRequest = URLRequest(url: u)
                webView.load(myRequest)
            } else {
                self.webView.evaluateJavaScript("if(resumeAll){resumeAll();}")
            }
            dateRefresh = Date()
            ThirdTabViewController.forceRefresh = false
        }
        let cpaasMode = PrefsUtil.getCpaasMode()
        let isBurger = cpaasMode == PrefsUtil.CPAAS_MODE_BURGER
        navigationController?.setNavigationBarHidden(!isBurger, animated: false)
        if isBurger {
            self.navigationController?.navigationBar.topItem?.title = Bundle.main.displayName
            self.navigationController?.navigationBar.setNeedsLayout()
        }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
            if (self.isUsingMyWebview() && self.webView.url != nil && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-main-only") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-main-only") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-main") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-commerce") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-video") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-main")) || ThirdTabViewController.showModal {
                ViewController.alwaysHideButton = true
                self.hideTabBar()
                ThirdTabViewController.atFirstPage = false
            } else {
                var viewController = UIApplication.shared.windows.first!.rootViewController
                if !(viewController is ViewController) {
                    viewController = self.parent
                }
                if ViewController.middleButton.isHidden {
                    ViewController.isExpandButton = false
                    if let viewController = viewController as? ViewController {
                        if viewController.tabBar.isHidden {
                            viewController.tabBar.isHidden = false
                            ViewController.middleButton.isHidden = false
                            ViewController.alwaysHideButton = false
                        }
                    }
                } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
                    DispatchQueue.main.async {
                        if let viewController = viewController as? ViewController {
                            if viewController.tabBar.isHidden {
                                viewController.tabBar.isHidden = false
                                ViewController.alwaysHideButton = false
                            }
                        }
                    }
                }
            }
        })
    }
    
    @objc func onShowAC(notification: NSNotification) {
        self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
        view.endEditing(true)
        resignFirstResponder()
    }
    
    @objc func onRefreshWebView(notification: NSNotification) {
        ThirdTabViewController.forceRefresh = true
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
            self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
        }
        self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
        view.endEditing(true)
        resignFirstResponder()
        ThirdTabViewController.inView = false
        self.webView.evaluateJavaScript("hideAddToCart();")
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if (self.lastContentOffset > scrollView.contentOffset.y && scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)) {
            showTabBar();
        }
        else if (self.lastContentOffset != 0 && self.lastContentOffset < scrollView.contentOffset.y && self.lastContentOffset >= 0) {
            hideTabBar();
        }
        self.lastContentOffset = scrollView.contentOffset.y
        self.collapseDocked()
    }

    
    @objc func collapseDocked() {
        if ViewController.isExpandButton {
            ViewController.expandButton()
        }
    }
    
    @objc func reloadWebView(_ sender: UIRefreshControl) {
        webView.reload()
        sender.endRefreshing()
    }

    func hideTabBar() {
        var viewController = UIApplication.shared.windows.first!.rootViewController
        if !(viewController is ViewController) {
            viewController = self.parent
        }
        if ViewController.middleButton.isDescendant(of: viewController!.view) {
            DispatchQueue.main.async {
                if ViewController.isExpandButton {
                    ViewController.expandButton()
                }
                ViewController.hideDockedButton()
                if let viewController = viewController as? ViewController {
                    viewController.tabBar.isHidden = true
                }
                ViewController.removeMiddleButton()
            }
        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
            DispatchQueue.main.async {
                if let viewController = viewController as? ViewController {
                    if !viewController.tabBar.isHidden {
                        viewController.tabBar.isHidden = true
                    }
                }
            }
        }
    }

    func showTabBar() {
        if(ViewController.alwaysHideButton){
            return
        }
        var viewController = UIApplication.shared.windows.first!.rootViewController
        if !(viewController is ViewController) {
            viewController = self.parent
        }
        if ViewController.middleButton.isHidden {
            if let viewController = viewController as? ViewController {
                viewController.tabBar.isHidden = false
                ViewController.middleButton.isHidden = false
            }
        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
            DispatchQueue.main.async {
                if let viewController = viewController as? ViewController {
                    if viewController.tabBar.isHidden {
                        viewController.tabBar.isHidden = false
                    }
                }
            }
        }
    }

    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
        scrollView.pinchGestureRecognizer?.isEnabled = false
    }


    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "checkProfile" {
            guard let dict = message.body as? [String: AnyObject],
                  let param1 = dict["param1"] as? String,
                  let param2 = dict["param2"] as? String else {
                return
            }
            if ViewController.checkIsChangePerson() {
                if param2 == "like" {
                    self.webView.evaluateJavaScript("likeProduct('\(param1)',1,true);")
                } else if param2 == "comment" {
                    self.webView.evaluateJavaScript("openComment('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
                } else if param2 == "report_user" {
                    self.webView.evaluateJavaScript("reportUser('\(param1)',true);")
                } else if param2 == "report_content" {
                    self.webView.evaluateJavaScript("reportContent('\(param1.split(separator: "|")[0])','\(param1.split(separator: "|")[1])',true);")
                } else if param2 == "block_user" {
                    self.webView.evaluateJavaScript("blockUser('\(param1)',true);")
                } else if param2 == "follow_user" {
                    self.webView.evaluateJavaScript("followUser('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
                } else if param2 == "homepage" || param2 == "gif" {
                    self.webView.evaluateJavaScript("window.location.href = '\(param1)';")
                } else if param2 == "block_content" {
                    self.webView.evaluateJavaScript("blockContent('\(param1)',true);")
                } else {
                    self.webView.evaluateJavaScript("openNewPost(true);")
                }
            } else {
                self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
            }
        } else if message.name == "setIsProductModalOpen" {
            guard let dict = message.body as? [String: AnyObject],
                  let param1 = dict["param1"] as? Bool else {
                return
            }
            if param1 {
                if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
                    self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
                }
            }
            ThirdTabViewController.showModal = param1
        } else if message.name == "toggleVoiceSearch" {
            if !isAllowSpeech {
                setupSpeech()
            } else {
                runVoice()
            }
        } else if message.name == "blockUser" {
            guard let dict = message.body as? [String: AnyObject],
                  let param1 = dict["param1"] as? String,
                  let param2 = dict["param2"] as? Bool else {
                return
            }
            if param2 {
                DispatchQueue.global().async {
                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
                        if response.isOk() {
                            DispatchQueue.main.async {
                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
                                        "ex_block" : "1"
                                    ], _where: "f_pin = '\(param1)'")
                                })
                            }
                        }
                    }
                }
            } else {
                DispatchQueue.global().async {
                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
                        if response.isOk() {
                            DispatchQueue.main.async {
                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
                                        "ex_block" : "0"
                                    ], _where: "f_pin = '\(param1)'")
                                })
                            }
                        }
                    }
                }
            }
        } else if message.name == "showAlert" {
            guard let dict = message.body as? [String: AnyObject],
                  let param1 = dict["param1"] as? String else {
                return
            }
            showToast(message: param1, controller: self.tabBarController!)
        } else if message.name == "blockUser" {
            guard let dict = message.body as? [String: AnyObject],
                  let param1 = dict["param1"] as? String,
                  let param2 = dict["param2"] as? Bool else {
                return
            }
            if param2 {
                DispatchQueue.global().async {
                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
                        if response.isOk() {
                            DispatchQueue.main.async {
                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
                                        "ex_block" : "1"
                                    ], _where: "f_pin = '\(param1)'")
                                })
                            }
                        }
                    }
                }
            } else {
                DispatchQueue.global().async {
                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
                        if response.isOk() {
                            DispatchQueue.main.async {
                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
                                        "ex_block" : "0"
                                    ], _where: "f_pin = '\(param1)'")
                                })
                            }
                        }
                    }
                }
            }
        } else if message.name == "tabShowHide" {
            guard let dict = message.body as? [String: AnyObject],
                  let param1 = dict["param1"] as? Bool else {
                return
            }
            if param1 {
                ViewController.alwaysHideButton = false
                showTabBar()
            } else {
                if self.viewIfLoaded?.window != nil {
                    ViewController.alwaysHideButton = true
                    hideTabBar()
                }
            }
        }
    }
    
    func setupSpeech() {

        self.speechRecognizer?.delegate = self

        SFSpeechRecognizer.requestAuthorization { (authStatus) in

            var isButtonEnabled = false

            switch authStatus {
            case .authorized:
                isButtonEnabled = true

            case .denied:
                isButtonEnabled = false
                print("User denied access to speech recognition")

            case .restricted:
                isButtonEnabled = false
                print("Speech recognition restricted on this device")

            case .notDetermined:
                isButtonEnabled = false
                print("Speech recognition not yet authorized")
            @unknown default:
                isButtonEnabled = false
            }

            OperationQueue.main.addOperation() {
                self.isAllowSpeech = isButtonEnabled
                if isButtonEnabled {
                    UserDefaults.standard.set(isButtonEnabled, forKey: "allowSpeech")
                    self.runVoice()
                }
            }
        }
    }
    
    func runVoice() {
        if !audioEngine.isRunning {
            alertController = UIAlertController(title: "Start Recording".localized(), message: "Say something, I'm listening!".localized(), preferredStyle: .alert)
            self.present(alertController, animated: true)
            self.webView.evaluateJavaScript("toggleVoiceButton(true)")
            self.startRecording()
        }
    }
    
    func startRecording() {

        // Clear all previous session data and cancel task
        if recognitionTask != nil {
            recognitionTask?.cancel()
            recognitionTask = nil
        }

        // Create instance of audio session to record voice
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(AVAudioSession.Category.record, mode: .default, options: [])
            try audioSession.setMode(AVAudioSession.Mode.measurement)
            try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
        } catch {
            print("audioSession properties weren't set because of an error.")
        }

        self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()

        let inputNode = audioEngine.inputNode

        guard let recognitionRequest = recognitionRequest else {
            fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
        }

        recognitionRequest.shouldReportPartialResults = true

        self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in

            var isFinal = false
            var text = ""

            if result != nil {
                text = result?.bestTranscription.formattedString ?? ""
                isFinal = (result?.isFinal)!
                self.alertController.dismiss(animated: true)
                self.audioEngine.stop()
                self.recognitionRequest?.endAudio()
            } else {
                self.alertController.dismiss(animated: true)
            }

            if error != nil || isFinal {
                if error == nil {
                    self.webView.evaluateJavaScript("toggleVoiceButton(false)")
                    self.webView.evaluateJavaScript("submitVoiceSearch('\(text)')")
                } else {
                    self.audioEngine.stop()
                    self.recognitionRequest?.endAudio()
                }
                inputNode.removeTap(onBus: 0)

                self.recognitionRequest = nil
                self.recognitionTask = nil

                self.isAllowSpeech = true
            }
        })

        let recordingFormat = inputNode.outputFormat(forBus: 0)
        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
            self.recognitionRequest?.append(buffer)
        }

        self.audioEngine.prepare()

        do {
            try self.audioEngine.start()
        } catch {
            print("audioEngine couldn't start because of an error.")
        }
    }
    
    func isUsingMyWebview() -> Bool{
        return PrefsUtil.getURLThirdTab() == "0" || PrefsUtil.getURLThirdTab() == "1" || PrefsUtil.getURLThirdTab() == "2" || PrefsUtil.getURLThirdTab() == "3" || PrefsUtil.getURLThirdTab() == "4"
    }

}

extension ThirdTabViewController: SFSpeechRecognizerDelegate {

    func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
        if available {
            self.isAllowSpeech = true
        } else {
            self.isAllowSpeech = false
        }
    }
}

extension ThirdTabViewController: WKUIDelegate {
      func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            if self.viewIfLoaded?.window != nil {
              if let urlStr = navigationAction.request.url?.absoluteString {
                  collapseDocked()
                  if urlStr.contains("nexilis/pages/tab1-main-only") || urlStr.contains("nexilis/pages/tab3-main-only") || urlStr.contains("nexilis/pages/tab1-main") || urlStr.contains("nexilis/pages/tab3-commerce") || urlStr.contains("nexilis/pages/tab1-video") || urlStr.contains("nexilis/pages/tab3-main") {
                      ViewController.alwaysHideButton = false
                      showTabBar()
                      ThirdTabViewController.atFirstPage = true
                  } else if isUsingMyWebview() {
                      ViewController.alwaysHideButton = true
                      hideTabBar()
                      ThirdTabViewController.atFirstPage = false
                  }
              }
            }
            decisionHandler(.allow)
      }
}
