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

import UIKit
import CocoaLumberjack

class SpeakerVolumesViewController: UIViewController {
	// MARK: Public Properties
	var playerGroup: IoTPlayerGroup? {
		didSet {
			if playerGroup != nil {
				update()
			}
		}
	}
	
	// MARK: UI Outlets
	@IBOutlet private weak var contentView: UIView?
	@IBOutlet private weak var tableView: UITableView?
	@IBOutlet private weak var bottomContainerView: UIView?
	@IBOutlet private weak var masterVolumeContentView: SpeakerSliderTableViewCellContentView?
	
	// MARK: Private Properties/Types
	private struct Segues {
		static let dismiss = "dismiss"
	}
	
	// private let operationsQueue = DispatchQueue(label: "com.qualcomm.qti.QueueOperationsHelper.blockingOperations")
	private var players = [IoTPlayer] ()
	private var playerGroupObserver: ObserverToken?
	private var playerObserver: ObserverToken?
}

// MARK: - Overridden Methods
extension SpeakerVolumesViewController {
	override func viewDidLoad() {
		contentView?.layer.cornerRadius = 4
		contentView?.clipsToBounds = true
		
		bottomContainerView?.layer.shadowRadius = 4
		bottomContainerView?.layer.shadowOffset = CGSize(width: 0, height: -5)
		bottomContainerView?.layer.shadowColor = UIColor.black.cgColor
		bottomContainerView?.layer.shadowOpacity = 0.25
		bottomContainerView?.layer.masksToBounds = false
		
		masterVolumeContentView?.sliderDidChange = { [weak self] cellOpt in
			guard let self = self else {
				return
			}
			
			self.didChangeVolume(nil)
		}

		// Accessibility
		tableView?.makeAccessible(Accessibility.SpeakerVolumesScreen.speakerList)
	}
	
	override func viewWillAppear(_ animated: Bool) {
		super.viewWillAppear(animated)
		
		let playerGroupHandler: (PlayerGroupNotification) -> () = { [weak self] notification in
			guard let self = self else { return }
			if notification.reason == .removed &&
				notification.playerGroup == self.playerGroup {
				// PlayerGroup's been deleted!!!
				self.performSegue(withIdentifier: Segues.dismiss, sender: self)
				return
			}
			
			self.updateForPlayerGroupChange(notification: notification)
			self.update()
		}
		
		playerGroupObserver = NotificationCenter.default.addObserver(forType: PlayerGroupNotification.self,
															  object: playerController,
															  queue: OperationQueue.main,
															  using: playerGroupHandler)
		
		
		let playerHandler: (PlayerNotification) -> () = { [weak self] notification in
			guard let self = self else { return }
			if notification.reason == .volumeStateChanged  {
				self.updateVolumeForPlayer(notification.player)
				return
			}
		}
		
		playerObserver = NotificationCenter.default.addObserver(forType: PlayerNotification.self,
																object: playerController,
																queue: OperationQueue.main,
																using: playerHandler)
		
		update()
	}
	
	override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        if playerGroupObserver != nil {
            NotificationCenter.default.removeObserver(playerGroupObserver!)
            playerGroupObserver = nil
        }

        if playerObserver != nil {
            NotificationCenter.default.removeObserver(playerObserver!)
            playerObserver = nil
        }
    }
}

// MARK: - UI Actions
extension SpeakerVolumesViewController {
    @IBAction func close(_ sender: UIButton) {
        performSegue(withIdentifier: Segues.dismiss, sender: self)
    }
}

// MARK: - Private Methods
extension SpeakerVolumesViewController {
    private func updateForPlayerGroupChange(notification: PlayerGroupNotification) {
        if notification.reason == .playerListChanged {
            update()
        } else if notification.reason == .volumeStateChanged {
            let volume = volumePercent(value: playerGroup?.volume ?? 0, maxVolume: playerGroup?.maxVolume ?? 0)
            masterVolumeContentView?.volumePercent = Int(volume)
        }
    }

    private func volumePercent(value: Double, maxVolume: Double) -> Double {
        var volume: Double = 0
        if (maxVolume > 0) {
            volume = min(value / maxVolume, 1.0) * 100.0
        }
        return volume
    }

    private func updateVolumeForPlayer(_ player: IoTPlayer) {
        guard let idx = players.firstIndex(of: player),
            let cell = tableView?.cellForRow(at: IndexPath(row: idx, section: 0)) as? SpeakerSliderTableViewCell else {
                return
        }
        let volume = volumePercent(value: player.volume, maxVolume: player.maxVolume)
        cell.volumePercent = Int(volume)
    }

    private func update() {
        players = playerGroup?.members.compactMap { member in
			return playerController.player(id: member.playerID)
        } ?? []

        tableView?.reloadData()

        masterVolumeContentView?.speakerName = NSLocalizedString("MASTER", comment: "master volume")
        let volume = volumePercent(value: playerGroup?.volume ?? 0, maxVolume: playerGroup?.maxVolume ?? 0)
        masterVolumeContentView?.volumePercent = Int(volume)
    }

    private func didChangeVolume(_ view: UIView?) {
        if let cell = view as? SpeakerSliderTableViewCell {
            // Need to set on player
            let volume = Double(cell.volumePercent) / 100.0 // Normalize 0->1
            if let ip = tableView?.indexPath(for: cell) {
                let player = players[ip.row]
                let maxVolume = player.maxVolume
                let requested = volume * maxVolume
                player.setVolume(requested,
                                 completion: { (success, e) in
                                    if let error = e {
                                        DDLogError("Error thrown setting volume: \(error)")
                                    }
                }, completionQueue: DispatchQueue.main)
            }
        } else {
            // Master volume
            let volume = Double(masterVolumeContentView!.volumePercent) / 100.0
            if let z = playerGroup {
                let maxVolume = z.maxVolume
                let requested = volume * maxVolume
                z.setVolume(requested,
                            completion: { (success, e) in
                                if let error = e {
                                    DDLogError("Error thrown setting volume: \(error)")
                                }
                }, completionQueue: DispatchQueue.main)
            }
        }
    }
}

// MARK: - UITableViewDelegate, UITableViewDataSource Conformance
extension SpeakerVolumesViewController : UITableViewDelegate, UITableViewDataSource {
	func numberOfSections(in tableView: UITableView) -> Int {
		return 1
	}
	
	func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
		return players.count
	}
	
	func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
		let cell = tableView.dequeueReusableCell(withIdentifier: "SpeakerSliderTableViewCell", for: indexPath) as! SpeakerSliderTableViewCell
		
		let player = players[indexPath.row]
		cell.speakerName = player.displayName
        cell.makeAccessible(player.displayName, doNotLocalizeForHuman: true)
		let volume = volumePercent(value: player.volume, maxVolume: player.maxVolume)
		cell.volumePercent = Int(volume)
		cell.sliderDidChange = { [weak self] cell in
			guard let self = self else {
					return
			}
			
			self.didChangeVolume(cell)
		}
		
		return cell
	}
	
	func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
		return CGFloat.leastNormalMagnitude
	}
	
	func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
		return CGFloat.leastNormalMagnitude
	}
	
	func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
		// Return false if you do not want the specified item to be editable.
		return false
	}
}
