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

import UIKit
import CocoaLumberjack

class SpeakerNameViewController: UITableViewController {
    struct VoiceUIGroupOption {
        let localizedName: String
        let available: Bool
    }
    private var voiceUIOptions = [VoiceUIGroupOption] ()
    private var inUseName: String?
//    private var nameToSet: String?
    var deviceID: String?
    var isRenamingZigbee = false
    var zigbeeDeviceID: UInt?
    private var zigbeeDevice: IoTZigbeeDevice?

    private var observers = [ObserverToken] ()
}

// MARK: - Overridden Methods
extension SpeakerNameViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Accessibility
        tableView?.accessibilityLabel = "Device Naming Name List"
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
		setCurrentInUseName()
        fetchVoiceUINamesAndReload()
        setUpObservers()
    }

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

// MARK: - Private Methods
extension SpeakerNameViewController {
    private func setUpObservers() {
        let deviceHandler: (DeviceNotification) -> () = { [weak self] notification in
            guard let self = self else { return }
            self.setCurrentInUseName()
            self.fetchVoiceUINamesAndReload()
        }

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

        let zigbeeHandler: (ZigbeeNotification) -> () = { [weak self] notification in
            guard let self = self else { return }
            self.setCurrentInUseName()
            self.fetchVoiceUINamesAndReload()
        }

        let zigbeeObserver = NotificationCenter.default.addObserver(forType: ZigbeeNotification.self,
                                                                    object: playerController,
                                                                    queue: OperationQueue.main,
                                                                    using: zigbeeHandler)

        let groupHandler: (PlayerGroupNotification) -> () = { [weak self] notification in
            guard let self = self else { return }
            self.setCurrentInUseName()
            self.fetchVoiceUINamesAndReload()
        }

        let groupObserver = NotificationCenter.default.addObserver(forType: PlayerGroupNotification.self,
                                                                    object: playerController,
                                                                    queue: OperationQueue.main,
                                                                    using: groupHandler)

        observers = [deviceObserver, zigbeeObserver, groupObserver]
    }

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

    private func setCurrentInUseName() {
        if let deviceID = deviceID,
            let device = playerController.device(id: deviceID) {
            if isRenamingZigbee {
                let zbDevices = device.zigbeeDevices
                zigbeeDevice = zbDevices.first { $0.identifier == zigbeeDevice?.identifier }
                inUseName = zigbeeDevice?.name
            } else {
                inUseName = device.displayName
                if inUseName?.isEmpty ?? true {
                    if let p = playerController.player(device: device) {
                        DDLogVerbose("Using device name from allplay!!!")
                        inUseName = p.displayName
                    }
                }
            }
//            nameToSet = inUseName
        }
    }

    private func fetchVoiceUINamesAndReload() {
        // Hard wired for now.
        let names = VoiceUIHelper.localizedVoiceUINames(domain: isRenamingZigbee ? .zigbee : .speaker,
                                                        playerController: playerController)
        let inUseNames = VoiceUIHelper.localizedVoiceUINamesInUse(domain: isRenamingZigbee ? .zigbee : .speaker,
                                                                  playerController: playerController,
                                                                  ignoringName: inUseName)

        voiceUIOptions = names.map { (name) -> VoiceUIGroupOption in
            let inUse = inUseNames.contains(name) && name != inUseName
            return VoiceUIGroupOption(localizedName: name, available: !inUse)
        }
        tableView?.reloadData()
    }

    private func showCustomNameEntryDialog() {
        let alert = UIAlertController(title: NSLocalizedString("Custom Device Name", comment: "Dialog title"),
                                      message: NSLocalizedString("Note: You will not be able to control this device using your voice if it has a custom name.", comment: "Dialog message"),
                                      preferredStyle: .alert)
        alert.addTextField { (textfield) in
            textfield.placeholder = NSLocalizedString("My Custom Device Name", comment: "Placeholder")
            textfield.makeAccessible(Accessibility.GroupNameScreen.customNameTextField)
        }
        let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: "Cancel"),
                                   style: .cancel,
                                   handler: nil)
        alert.addAction(cancel)
        let doIt = UIAlertAction(title: NSLocalizedString("Use this name", comment: "Action"),
                                 style: .default,
                                 handler: { _ in
                                    if let newName = alert.textFields?.first?.text,
                                        newName.count > 0 {
                                        self.setName(newName: newName)
                                    }
        } )
        alert.addAction(doIt)
        present(alert,
                animated: true,
                completion: nil)
    }

    private func setName(newName: String) {
        if let deviceID = deviceID,
            let device = playerController.device(id: deviceID) {
            if isRenamingZigbee {
                if let id = zigbeeDeviceID {
                    device.startSetZbDeviceName(newName,
                                                identifer: id,
                                                completion: nil,
                                                completionQueue: nil)
                }

            } else {
                device.setDisplayName(newName,
                                      completion: nil,
                                      completionQueue: nil)
            }
        }
    }

    private func haveSelectedVoiceUIName() -> (Bool) {
        let usingVoiceUIOption = voiceUIOptions.contains(where: { option in
            return inUseName?.localizedCompare(option.localizedName) == ComparisonResult.orderedSame
        })
        return usingVoiceUIOption
    }
}

// MARK: - UITableViewDelegate, UITableViewDataSource Conformance
extension SpeakerNameViewController {
    override func numberOfSections(in tableView: UITableView) -> Int {
        if let deviceID = deviceID,
            let _ = playerController.device(id: deviceID) {
            return 2
        } else {
            return 0
        }
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let deviceID = deviceID,
            let _ = playerController.device(id: deviceID) {
            return section == 0 ? voiceUIOptions.count : 1
        } else {
            return 0
        }
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "NameTableViewCell", for: indexPath)
        if let deviceID = deviceID,
            let _ = playerController.device(id: deviceID) {
            cell.textLabel?.textColor = ColorCompat.label
            switch indexPath.section {
            case 0:
                let option = voiceUIOptions[indexPath.row]
                cell.textLabel?.text = option.localizedName
                if !option.available {
                    cell.textLabel?.textColor = ColorCompat.secondaryLabel
                }
                let namesMatch = inUseName?.localizedCompare(option.localizedName) == ComparisonResult.orderedSame
                cell.accessoryType = namesMatch ? .checkmark : .none
                if namesMatch {
                    cell.makeAccessible(option.localizedName, localizableSuffix: Accessibility.MediaLibrary.CellSuffix.selectedSuffix)
                } else {
                    cell.makeAccessible(option.localizedName, doNotLocalizeForHuman: true)
                }
            case 1:
                // Checkmark is shown if name is not one of other options
                let showCheckmark = !haveSelectedVoiceUIName()
                cell.textLabel?.text = NSLocalizedString("Use Custom Name", comment: "Use Custom Name")
                cell.accessoryType = showCheckmark ? .checkmark : .none
                if showCheckmark {
                    cell.makeAccessible(Accessibility.GroupNameScreen.useCustomName + Accessibility.MediaLibrary.CellSuffix.selectedSuffix)
                } else {
                    cell.makeAccessible(Accessibility.GroupNameScreen.useCustomName)
                }
            default:
                break
            }
        }
        return cell
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if section == 0 {
            return NSLocalizedString("AVAILABLE VOICE SUPPORTED NAMES", comment: "GROUP NAME")
        } else {
            return ""
        }
    }

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

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 60.0
    }

    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return false
    }

    override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        if indexPath.section == 0 {
            return voiceUIOptions[indexPath.row].available ? indexPath : nil
        } else {
            return indexPath
        }
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: false)
        if let deviceID = deviceID,
            let _ = playerController.device(id: deviceID) {
            switch indexPath.section {
            case 0:
                setName(newName: voiceUIOptions[indexPath.row].localizedName)
            case 1:
                showCustomNameEntryDialog()
            default:
                break
            }
        }
    }
}
