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

import UIKit

protocol GroupingNameViewControllerDelegate: class {
    func nameController(_ controller: GroupingNameViewController, didSelectName newName: String)
}

class GroupingNameViewController: MiniPlayerEmbeddingViewController {
    struct VoiceUIGroupOption {
        let localizedName: String
        let available: Bool
    }

    weak var nameDelegate: GroupingNameViewControllerDelegate?
    var voiceUIOptions = [VoiceUIGroupOption] ()
    var currentNameChoice: String?
    var observers = [ObserverToken] ()
	@IBOutlet private weak var tableView: UITableView?

    override func handlePlayerGroupNotification(_ notification: PlayerGroupNotification) {
        super.handlePlayerGroupNotification(notification)
        fetchVoiceUINamesAndReload()
    }
}

// MARK: - Overridden Methods
extension GroupingNameViewController {
    override func viewDidLoad() {
        hasSearchButton = false

        super.viewDidLoad()
        // Accessibility
        tableView?.makeAccessible(Accessibility.GroupNameScreen.namesList)
        fetchVoiceUINamesAndReload()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let deviceHandler: (DeviceNotification) -> () = { [weak self] notification in
            guard let self = self else { return }
            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.fetchVoiceUINamesAndReload()
        }

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

        observers = [deviceObserver, zigbeeObserver]
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        observers.forEach({
            NotificationCenter.default.removeObserver($0)
        })
        observers.removeAll()
    }
}

// MARK: - Private Methods
extension GroupingNameViewController {
    private func fetchVoiceUINamesAndReload() {
        // Hard wired for now.
        let names = VoiceUIHelper.localizedVoiceUINames(domain: .group, playerController: playerController)
        let inUseNames = VoiceUIHelper.localizedVoiceUINamesInUse(domain: .group,
                                                                  playerController: playerController,
                                                                  ignoringName: playerGroup?.displayName)

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

    private func showCustomNameEntryDialog() {
        let alert = UIAlertController(title: NSLocalizedString("Custom Group Name", comment: "Dialog title"),
                                      message: NSLocalizedString("Note: You will not be able to control this group using your voice if it has a custom name.", comment: "Dialog message"),
                                      preferredStyle: .alert)
        alert.addTextField { (textfield) in
            textfield.makeAccessible(Accessibility.GroupNameScreen.customNameTextField)
            textfield.placeholder = NSLocalizedString("My Custom Group Name", comment: "Placeholder")
        }
        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.currentNameChoice = newName
                                        self.notifyDelegate(newName: newName)
                                        self.tableView?.reloadData()
                                    }
        } )
        alert.addAction(doIt)
        present(alert,
                animated: true,
                completion: nil)
    }

    private func notifyDelegate(newName: String) {
        if let del = nameDelegate {
            del.nameController(self, didSelectName: newName)
        }
    }

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

    private func usingDefaultName() -> (Bool) {
        if let pg = playerGroup {
            if !pg.isConvenienceGroup {
                return false
            }
            return currentNameChoice?.localizedCompare(pg.displayName) == ComparisonResult.orderedSame
        } else {
            return false
        }
    }
}

// MARK: - UITableViewDelegate, UITableViewDataSource Conformance
extension GroupingNameViewController: UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return playerGroup != nil ? 2 : 0
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let pg = playerGroup {
            switch section {
            case 0:
                return voiceUIOptions.count
            default:
                return pg.isConvenienceGroup ? 2 : 1
            }
        } else {
            return 0
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "NameTableViewCell", for: indexPath)
        if let pg = playerGroup {
            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 = UIColor.lightGray
                }
                let namesMatch = currentNameChoice?.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:
                if !pg.isConvenienceGroup || indexPath.row > 0 {
                    // Checkmark is shown if name is not one of other options
                    let showCheckmark = !(haveSelectedVoiceUIName() || usingDefaultName())
                    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)
                    }
                } else {
                    let showCheckmark = !haveSelectedVoiceUIName() && usingDefaultName()
                    cell.textLabel?.text = NSLocalizedString("Use Default Name", comment: "Use Default Name")
                    cell.accessoryType = showCheckmark ? .checkmark : .none
                    if showCheckmark {
                        cell.makeAccessible(Accessibility.GroupNameScreen.useDefaultName + Accessibility.MediaLibrary.CellSuffix.selectedSuffix)
                    } else {
                        cell.makeAccessible(Accessibility.GroupNameScreen.useDefaultName)
                    }
                }
            default:
                break
            }
        }
        return cell
    }

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

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

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

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

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

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: false)
        if let pg = playerGroup {
            switch indexPath.section {
            case 0:
                currentNameChoice = voiceUIOptions[indexPath.row].localizedName
                notifyDelegate(newName: currentNameChoice!)
                tableView.reloadData()
            case 1:
                if !pg.isConvenienceGroup  || indexPath.row > 0 {
                    // Custom
                    showCustomNameEntryDialog()
                } else {
                    // Use default
                    currentNameChoice = playerGroup?.displayName
                    notifyDelegate(newName: currentNameChoice!)
                    tableView.reloadData()
                }
            default:
                break
            }
        }
    }
}
