//
//  MainViewController.swift
//  BleDemo
//
//  Created by CT-Armin.Budiman on 3/9/20.
//  Copyright © 2020 Cartrack. All rights reserved.
//

import UIKit
import CoreBluetooth
import CartrackBleLockSDK

class MainViewController: UIViewController {

    var bleTerminal: BleTerminal?

    @IBOutlet weak var authKeyLabel: UILabel!

    @IBOutlet weak var terminalIdTextField: UITextField!
    @IBOutlet weak var configureTerminalButton: UIButton!

    @IBOutlet weak var authKeyTextField: UITextField!
    @IBOutlet weak var saveAuthKeyButton: UIButton!
    @IBOutlet weak var connectButton: UIButton!
    @IBOutlet weak var disconnectButton: UIButton!
    @IBOutlet weak var removeKeyButton: UIButton!

    @IBOutlet weak var vehicleStatsButton: UIButton!
    @IBOutlet weak var lockStateButton: UIButton!
    @IBOutlet weak var unlockButton: UIButton!
    @IBOutlet weak var lockButton: UIButton!
    @IBOutlet weak var unlockWithNoKeyFobButton: UIButton!
    @IBOutlet weak var ignitionStateButton: UIButton!
    @IBOutlet weak var headlightButton: UIButton!
    @IBOutlet weak var hornButton: UIButton!

    @IBOutlet weak var lockStateLabel: UILabel!
    @IBOutlet weak var rssiLabel: UILabel!
    @IBOutlet weak var versionLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.rssiLabel.text = ""
        self.showSavedInfo()
        self.setVersionAndBuildNumber()
        self.updateViewsState()
    }

    private func showSavedInfo() {
        self.terminalIdTextField.text = UserDefaults.standard.value(forKey: "terminal_id") as? String ?? ""
        self.authKeyTextField.text = self.bleTerminal?.authKey
    }

    private func setVersionAndBuildNumber() {
        if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String,
           let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String {          self.versionLabel.text = "v\(version) (\(build))"
        }
    }

    @IBAction func configureTerminalButtonTapped(_ sender: Any) {
        self.setTerminalID()
    }

    @IBAction func saveAuthKeyButtonTapped(_ sender: Any) {
        self.saveAuthKey()
    }
  
    @IBAction func connectButtonTapped(_ sender: Any) {
        LoaderView.show("Connecting")
        self.bleTerminal?.connect()
        self.updateViewsState()
    }
   
    @IBAction func disconnectButtonTapped(_ sender: Any) {
        LoaderView.show()
        self.bleTerminal?.disconnect()
    }

    @IBAction func removeKeyButtonTapped(_ sender: Any) {
        self.bleTerminal?.removeAuthKey()
        self.updateViewsState()
        if self.bleTerminal?.hasKey ?? false {
          self.showMessage(title: "Remove Key failed", message: "")
        } else {
          self.showMessage(title: "Remove Key Successful", message: "")
        }

    }

    @IBAction func unlockButtonTapped(_ sender: Any) {
        LoaderView.show()
        self.bleTerminal?.sendAction(.unlock)
        self.updateViewsState()
    }
    
    @IBAction func lockButtonTapped(_ sender: Any) {
        LoaderView.show()
        self.bleTerminal?.sendAction(.lock)
        self.updateViewsState()
    }

    @IBAction func unlockWithNoKeyFobButtonTapped(_ sender: UIButton) {
        LoaderView.show()
        self.bleTerminal?.sendAction(.unlockNoKeyFob)
        self.updateViewsState()
    }
    
    @IBAction func headlightButtonTapped(_ sender: Any) {
        LoaderView.show()
        self.bleTerminal?.sendAction(.headlight)
        self.updateViewsState()
    }
    
    @IBAction func hornButtonTapped(_ sender: Any) {
        LoaderView.show()
        self.bleTerminal?.sendAction(.horn)
        self.updateViewsState()
    }
    
    @IBAction func lockStateButtonTapped(_ sender: Any) {
        LoaderView.show()
        self.bleTerminal?.sendAction(.lockState)
        self.updateViewsState()
    }

    @IBAction func vehicleStatsButtonTapped(_ sender: Any) {
        LoaderView.show()
        self.bleTerminal?.getVehicleStats()
        self.updateViewsState()
    }

    private func setTerminalID() {
        self.terminalIdTextField.resignFirstResponder()

        guard let terminalId = self.terminalIdTextField.text, !terminalId.isEmpty else {
          self.showMessage(title: "", message: "Please enter a Terminal ID")
          return
        }

        self.bleTerminal = BleService.getTerminal(terminalID: terminalId)
        self.bleTerminal?.delegate = self

        UserDefaults.standard.set(terminalId, forKey: "terminal_id")

        self.showMessage(title: "Set Terminal ID successful", message: "")
        self.updateViewsState()
    }

    private func saveAuthKey() {
        self.authKeyTextField.resignFirstResponder()

        guard let authKey = self.authKeyTextField.text, !authKey.isEmpty else {
          showMessage(title: "", message: "Please enter an authentication key")
          return
        }

        self.bleTerminal?.saveAuthKey(authKey: authKey)
    }

    @IBAction func ignitionStateButtonTapped(_ sender: UIButton) {
      LoaderView.show()
      bleTerminal?.sendAction(.ignitionState)
      updateViewsState()
    }
    
    private func showMessage(title: String, message: String) {
        let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
        self.present(alertController, animated: true, completion: nil)
    }

    private func verifyUrl(urlString: String?) -> Bool {
        if let urlString = urlString {
          if let url = NSURL(string: urlString) {
            return UIApplication.shared.canOpenURL(url as URL)
          }
        }
        return false
    }
    
    private func updateViewsState() {
        let initialized = self.bleTerminal != nil
        let connectionState = self.bleTerminal?.connectionState ?? BleConnectionState.disconnected
        self.authKeyLabel.text = initialized ? (self.bleTerminal?.hasKey ?? false ? self.bleTerminal?.authKey : "Keychain is empty") : "Ble Terminal is not initialize"

        self.saveAuthKeyButton.isEnabled = initialized
        self.connectButton.isEnabled = connectionState == .disconnected && initialized
        self.disconnectButton.isEnabled = connectionState == .connected
        self.removeKeyButton.isEnabled = initialized
        self.lockStateLabel.text = "Lock State: \(self.bleTerminal?.lockState ?? .unknown)".capitalized

      [self.unlockButton, self.lockButton, self.headlightButton, self.hornButton, self.lockStateButton, self.unlockWithNoKeyFobButton, self.vehicleStatsButton, self.ignitionStateButton].forEach {
            $0?.isEnabled = initialized && connectionState == .connected
        }
    }
}

extension MainViewController: UITextFieldDelegate {
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}

extension MainViewController: BleTerminalDelegate {

    func bleTerminalDidSavedKey(terminal: BleTerminal, error: BleError?) {
        if let error = error {
          self.showMessage(title: "Save Key Failed", message: "\(error.errorCode) \(error.localizedDescription)")
        } else {
          self.showMessage(title: "Save Key Successful", message: "Successful save authentication key!")
        }
        self.updateViewsState()
        LoaderView.hide()
    }
    
    func bleTerminalDidConnect(terminal: BleTerminal, error: BleError?) {
        if let error = error {
          self.showMessage(title: "Failed to connect", message: "\(error.errorCode) \(error.localizedDescription)")
        }
        self.updateViewsState()
        LoaderView.hide()
    }
    
    func bleTerminalDidAction(terminal: BleTerminal, action: BleAction, error: BleError?) {
        if let error = error {
          self.showMessage(title: "Action Failed", message: "[\(error.actionCode)] [\(action)] Failed\nReason: [\(error.errorCode)]\(error.localizedDescription)")
        } else {
            switch action {
            case .lockState:
                self.showMessage(title: "Action", message: "Vehicle's door is \(terminal.lockState)")
            case .lock:
                self.showMessage(title: "Action", message: "Lock Action Success\nLock state: [\(terminal.lockState)]")
            case .unlock:
                self.showMessage(title: "Action", message: "Unlock Action Success\nLock state: [\(terminal.lockState)]")
            case .unlockNoKeyFob:
                self.showMessage(title: "Action", message: "Unlock with No Key Fob Action Success\nLock state: [\(terminal.lockState)]")
            case .horn:
                self.showMessage(title: "Action", message: "Horn Action Success")
            case .headlight:
                showMessage(title: "Action", message: "Headlight Action Success")
            case .ignitionState:
              showMessage(title: "Action", message: "Vehicle's ignition state is \(terminal.ignitionState)")
            @unknown default:
                break
            }
        }
        self.updateViewsState()
        LoaderView.hide()
    }

    func bleTerminalDidGetVehicleStats(terminal: BleTerminal, vehicleStats: VehicleStats?, error: BleError?) {
        if let error = error {
          self.showMessage(title: "Action Failed", message: "[\(error.actionCode)] get vehicle stats Failed\nReason: [\(error.errorCode)] \(error.localizedDescription)")
        } else {
            let vc = self.storyboard?.instantiateViewController(withIdentifier: "VehicleStatsViewController") as! VehicleStatsViewController
            vc.vehicleStats = vehicleStats
            self.navigationController?.pushViewController(vc, animated: true)
        }
        self.updateViewsState()
        LoaderView.hide()
    }
    
    func bleTerminalDisconnected(terminal: BleTerminal) {
        self.showMessage(title: "", message: "Disconnected")
        self.updateViewsState()
        self.rssiLabel.text = ""
        LoaderView.hide()
    }
    
    func bleTerminalSignalUpdate(rssi: Int, strength: BleSignalStrength) {
        self.rssiLabel.text = "RSSI: \(rssi) dBm (\(strength))"
    }
}

class LoaderView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        let activityIndicator = UIActivityIndicatorView(style: .whiteLarge)
        activityIndicator.backgroundColor = UIColor.black.withAlphaComponent(0.7)
        activityIndicator.frame = frame
        addSubview(activityIndicator)
        activityIndicator.startAnimating()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public static func show(_ text: String = "") {
        hide()
        let window = UIApplication.shared.keyWindow!
        let loaderView = LoaderView(frame: window.bounds)
        let label = UILabel(frame: window.bounds)
        label.text = text
        label.transform = CGAffineTransform(translationX: 0, y: 40)
        label.textAlignment = .center
        label.textColor = .white
        loaderView.addSubview(label)
        window.addSubview(loaderView)
    }
    
    public static func hide() {
        if let window = UIApplication.shared.keyWindow, let loaderView = window.subviews.first(where: { $0 is LoaderView}) {
            loaderView.removeFromSuperview()
        }
    }
}

