//
// © 2018-2020 Qualcomm Technologies, Inc. and/or its subsidiaries. All rights reserved.
//

import UIKit

class VoiceUISettingsTableViewCell: UITableViewCell {
    static let reuseIdentifier = "VoiceUISettingsTableViewCell"
    @IBOutlet weak var titleLabel: UILabel!
}

struct SettingsOptionsRequiredObservers: OptionSet {
    let rawValue: Int

    static let device = SettingsOptionsRequiredObservers(rawValue: 1 << 0)
    static let player = SettingsOptionsRequiredObservers(rawValue: 1 << 1)
    static let voiceUI = SettingsOptionsRequiredObservers(rawValue: 1 << 2)
}

struct SettingsOptionsSourceItem {
    let cellTitle: String
    let unlocalizedAccessibilityTitle: String
}

protocol SettingsOptionsSource {
	func isCurrentSelection(at index: Int) -> Bool
    func itemSelected(at index: Int)
    func item(at index: Int) -> SettingsOptionsSourceItem
    func numberOfItems() -> Int
    func loadOptions()
    func requiredObservers() -> [SettingsOptionsRequiredObservers]
}

class SettingsOptionsViewController: UITableViewController {
    var deviceID: String?
    var source: SettingsOptionsSource?

    // MARK: Private Properties
    private var observers = [ObserverToken] ()
}

extension SettingsOptionsViewController {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        setUpObservers()
        reloadState()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        removeObservers()
    }
}

extension SettingsOptionsViewController {
    private func reloadState() {
        source!.loadOptions()
        tableView.reloadData()
    }

    private func setUpObservers() {
        observers.removeAll()

        guard let options = source?.requiredObservers() else {
            return
        }

        if options.contains(.device) {
            let deviceHandler: (DeviceNotification) -> () = { [weak self] notification in
                guard let self = self else { return }

                if notification.reason == .removed {
                    self.reloadState()
                }
            }

            let deviceObserver = NotificationCenter.default.addObserver(forType: DeviceNotification.self,
                                                                        object: playerController,
                                                                        queue: OperationQueue.main,
                                                                        using: deviceHandler)
            observers.append(deviceObserver)
        }
        // ************

        if options.contains(.voiceUI) {
            let voiceUIHandler: (VoiceUINotification) -> () = { [weak self] notification in
                guard let self = self else { return }

                self.reloadState()
            }

            let voiceUIObserver = NotificationCenter.default.addObserver(forType: VoiceUINotification.self,
                                                                         object: playerController,
                                                                         queue: OperationQueue.main,
                                                                         using: voiceUIHandler)
            observers.append(voiceUIObserver)
        }

        if options.contains(.player) {
            let playerHandler: (PlayerNotification) -> () = { [weak self] notification in
                guard let self = self else { return }

                self.reloadState()
            }

            let playerObserver = NotificationCenter.default.addObserver(forType: PlayerNotification.self,
                                                                        object: playerController,
                                                                        queue: OperationQueue.main,
                                                                        using: playerHandler)
            observers.append(playerObserver)
        }
    }

    private func removeObservers() {
        observers.forEach {
            NotificationCenter.default.removeObserver($0)
        }
        observers.removeAll()
    }

}
    

extension SettingsOptionsViewController {
    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return source!.numberOfItems()
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: VoiceUISettingsTableViewCell.reuseIdentifier) as? VoiceUISettingsTableViewCell
        if cell == nil {
            cell = VoiceUISettingsTableViewCell()
        }

        let item = source!.item(at: indexPath.row)
        let selected = source!.isCurrentSelection(at: indexPath.row)

        cell?.titleLabel?.text = item.cellTitle
        if selected {
			cell?.makeAccessible(item.unlocalizedAccessibilityTitle,
                                 second: Accessibility.SettingsScreens.selectedSuffix)
            cell?.accessoryType = .checkmark
        } else {
			cell?.makeAccessible(item.unlocalizedAccessibilityTitle)
            cell?.accessoryType = .none
        }
        return cell!
    }

    override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return CGFloat.leastNormalMagnitude
    }

    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return CGFloat.leastNormalMagnitude
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: false)

        if !source!.isCurrentSelection(at: indexPath.row) {
            source!.itemSelected(at: indexPath.row)
        }
    }
}
