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

import UIKit
import CocoaLumberjack

class QueueViewController: UIViewController {
	var playerGroup: IoTPlayerGroup?
	
	// MARK: UI Outlets
	@IBOutlet private weak var emptyView: UIView?
    @IBOutlet private weak var loadingView: UIView?
	@IBOutlet private weak var collectionView: UICollectionView?
	@IBOutlet private weak var numberOfItemsLabel: UILabel?
	
	// MARK: Private Properties/Types
    private struct Segues {
        static let popSegue = "popSegue"
		static let dismiss = "dismiss"
    }
	
	private enum QueueOptions: Int {
		case saveAsPlaylist = 0
		case clearQueue
		
		func toString() -> String {
			switch self {
			case .saveAsPlaylist: return NSLocalizedString("Save as Playlist", comment: "Option")
			case .clearQueue: return NSLocalizedString("Clear Queue", comment: "Option")
			}
		}
		
		static func from(string: String) -> QueueOptions? {
			if string == QueueOptions.saveAsPlaylist.toString() {
				return QueueOptions.saveAsPlaylist
			}
			if string == QueueOptions.clearQueue.toString() {
				return QueueOptions.clearQueue
			}
			return nil
		}
	}
	
	private var observers = [ObserverToken] ()
	private var collectionViewHelper: MusicListDisplayHelper!
	private var queueDataSource: MusicListDataSource?
	private var queueDelegate: QueueDataSourceDelegate?
	private var playlistHelper: NewUserPlaylistHelper!
	
	// MARK: Deinit
	deinit {
		observers.forEach { NotificationCenter.default.removeObserver($0) }
		observers.removeAll()
	}
}

// MARK: - Overridden Methods
extension QueueViewController {
    override func viewDidLoad() {
        assert(playerGroup != nil)
        super.viewDidLoad()
		
		setUpHelpers()

        playlistHelper = NewUserPlaylistHelper(viewController: self, mediaItemProvider: { [weak self] (completion) in
            guard let self = self,
                let playlist = self.playerGroup?.playlist else {
                    completion([])
                    return
            }
            // Get all the items
			let count = playlist.count
            playlist.getItemsIn(NSMakeRange(0, Int(count)),
                                completion: { (success, items, e) in
                                    if !success, let error = e {
                                        DDLogError("Could not create media items: \(error)")
                                    }
                                    completion(items)
            }, completionQueue: DispatchQueue.main)
		})
        
        title = NSLocalizedString("QUEUE", comment: "Queue text")
        
        if let closeImage = UIImage(named: "btn-down"),
            let closeImagePressed = UIImage(named: "btn-down-pressed") {
            let resizableCloseImage = closeImage.resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: closeImage.size.width-1, bottom: 0, right: 0))
            let resizableCloseImagePressed = closeImagePressed.resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: closeImagePressed.size.width-1, bottom: 0, right: 0))
            let leftBarButton = UIBarButtonItem(title: " ", style: .plain, target: self, action: #selector(didTapModalClose(_:)))
            leftBarButton.setBackgroundImage(resizableCloseImage, for: .normal, barMetrics: .default)
            leftBarButton.setBackgroundImage(resizableCloseImagePressed, for: .highlighted, barMetrics: .default)
			leftBarButton.makeAccessible(Accessibility.QueueScreen.closeButton)
            navigationItem.leftBarButtonItem = leftBarButton
        }
        
        if let nowPlaying = UIImage(named: "btn-now-playing"),
            let nowPlayingPressed = UIImage(named: "btn-now-playing-pressed") {
            let resizableNowPlayingImage = nowPlaying.resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: nowPlaying.size.width-1))
            let resizableNowPlayingImagePressed = nowPlayingPressed.resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: nowPlayingPressed.size.width-1))
            let rightBarButton = UIBarButtonItem(title: " ", style: .plain, target: self, action: #selector(didTapNowPlaying(_:)))
            rightBarButton.setBackgroundImage(resizableNowPlayingImage, for: .normal, barMetrics: .default)
            rightBarButton.setBackgroundImage(resizableNowPlayingImagePressed, for: .highlighted, barMetrics: .default)
			rightBarButton.makeAccessible(Accessibility.QueueScreen.nowPlayingButton)
            navigationItem.rightBarButtonItem = rightBarButton
        }

        setOverlayViewVisbility()
		
		guard let playlist = playerGroup?.playlist else {
			return
		}
		
		// For first luanch we scroll the currently playing item to the top.
		let currentIndex = playlist.indexPlaying

        let haveItems = queueDataSource?.numberOfItems() ?? 0 > 0
		if haveItems && currentIndex >= 0 {
			let path = IndexPath(row: Int(currentIndex), section: 0)
			collectionView?.scrollToItem(at: path, at: .top, animated: false)
		}

		setupObservers()
    }
}

// MARK: - UI Actions
extension QueueViewController {
	@objc private func didTapNowPlaying(_ sender: AnyObject?) {
		// Perform unwind segue
		performSegue(withIdentifier: Segues.popSegue, sender: self)
	}

	override func didTapModalClose(_ sender: AnyObject?) {
		performSegue(withIdentifier: Segues.dismiss, sender: self)
	}
	
	@IBAction private func didTapQueueActionsButton(_ sender: UIButton) {
		let options = [QueueOptions.saveAsPlaylist.toString(),
					   QueueOptions.clearQueue.toString()]
		let alertController = UIAlertController(title: nil,
												message: nil,
												preferredStyle: .actionSheet)
		
		alertController.popoverPresentationController?.sourceView = sender
		alertController.popoverPresentationController?.sourceRect = sender.bounds
		
		let optionAction: (UIAlertAction) -> () = { action in
			guard let title = action.title else {
				return
			}
			
			self.doOption(title)
		}
		for optionIndex in 0..<options.count {
			let option = options[optionIndex]
			alertController.addAction(UIAlertAction(title: option,
													style: .default,
													handler: optionAction))
		}
		
		alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "Cancel"),
												style: .cancel,
												handler: nil))
		
		self.present(alertController, animated: true)
	}

    private func didSelect(row: Int, item: MusicListDisplayHelperItem) {
        queueDataSource?.performOption(title: MusicLibraryOptions.playNow.toString(), at: row)
    }
}

	
// MARK: - Private Methods
extension QueueViewController {
    private func setOverlayViewVisbility() {
        let haveFetchedItems = queueDataSource?.numberOfItems() ?? 0 > 0

        if haveFetchedItems {
            emptyView?.alpha = 0.0
            loadingView?.alpha = 0.0
        } else if (playerGroup?.playlist?.count ?? 0) > 0 {
            emptyView?.alpha = 0.0
            loadingView?.alpha = 1.0
        } else {
            // We have no items and aren't expecting any
            emptyView?.alpha = 1.0
            loadingView?.alpha = 0.0
        }
    }

	private func setUpHelpers() {
		queueDelegate = QueueDataSourceDelegate(playerGroup: playerGroup!)
		queueDataSource = MusicListDataSource(playerGroup: playerGroup!,
											  playerController: playerController,
											  delegate: queueDelegate!)
		queueDataSource?.queueDelegate = queueDelegate
		
		collectionViewHelper = MusicListDisplayHelper(dataSources: [queueDataSource!],
													  viewController: self,
													  collectionView: collectionView!,
													  dragAllowed: true,
													  countUpdater:  { [weak self] numberOfItems in
														guard let self = self,
															let label = self.numberOfItemsLabel else {
																return
														}
														
														self.setOverlayViewVisbility()
														// NOTE: We do not pluralize here - we should do it in a .stringsdict file
														// https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/LocalizingYourApp/LocalizingYourApp.html#//apple_ref/doc/uid/10000171i-CH5-SW10
														let songsStr = String.localizedStringWithFormat("%d SONGS", numberOfItems)
														label.text = songsStr
			},
                                                      onItemSelected: { [weak self] indexPath, item in
                                                        guard let self = self else {
                                                            return
                                                        }
                                                        self.didSelect(row: indexPath.row, item: item)

        })
	}

	private func doOption(_ title: String) {
		guard let option = QueueOptions.from(string: title) else {
			return
		}
		switch option {
		case .saveAsPlaylist:
			saveAsPlaylist()
		case .clearQueue:
			clearQueue()
		}
	}

    private func clearQueue() {
        let alertController = UIAlertController(title: nil,
                                                message: NSLocalizedString("Are you sure you want to remove all songs from the queue?",
                                                                           comment: "Confirmation dialog"),
                                                preferredStyle: .alert)

        alertController.addAction(UIAlertAction(title: NSLocalizedString("Clear Queue", comment: "Confirmation dialog"),
                                                style: .destructive,
                                                handler: { action in
                                                    if let playlist = self.playerGroup?.playlist {
                                                        playlist.clear(completion: { (success, e) in
                                                            if !success, let error = e {
                                                                DDLogError("Couldn't clear playlist: \(error)")
                                                            }
                                                        }, completionQueue: DispatchQueue.main)
                                                    }
        }))

		alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "Cancel"),
												style: .cancel,
												handler: nil))
		
		self.present(alertController, animated: true, completion: nil)
	}
	
	private func saveAsPlaylist() {
		playlistHelper.saveAsPlaylist(completion: nil)
	}

	private func setupObservers() {
		let playerGroupHandler: (PlayerGroupNotification) -> () = { [weak self] notification in
			guard
                let self = self,
                notification.playerGroup == self.playerGroup else {
					return
			}
			if notification.reason == .removed {
				// The playerGroup we're watching was removed.
				self.collectionView?.delegate = nil
				self.collectionView?.dataSource = nil
				self.performSegue(withIdentifier: Segues.popSegue, sender: self)
			}
			
			if notification.reason == .playStateChanged {
				let oldIndex = self.queueDelegate!.currentPlayingIndex
				self.queueDelegate?.updateCurrentPlayingItem()
				let newIndex = self.queueDelegate!.currentPlayingIndex
				if oldIndex >= 0 && oldIndex < self.queueDataSource!.numberOfItems()  {
					self.queueDataSource?.dispatchUpdateRequest(request: .reload(section: 0, row: oldIndex))
				}
				if newIndex != oldIndex && newIndex >= 0 && newIndex < self.queueDataSource!.numberOfItems(){
					self.queueDataSource?.dispatchUpdateRequest(request: .reload(section: 0, row: newIndex))
				}
			}
		}
		
		let playerGroupObserver = NotificationCenter.default.addObserver(forType: PlayerGroupNotification.self,
																  object: playerController,
																  queue: OperationQueue.main,
																  using: playerGroupHandler)
		
		observers.append(playerGroupObserver)
		
		// **********
		
		let playlistHandler: (PlaylistNotification) -> () = { [weak self] notification in
			guard
                let self = self,
                notification.playlist == self.playerGroup?.playlist else {
					return
			}
			
			if !self.queueDelegate!.expectingPlaylistChanges {
				// Something has happened we did not expect - reload.
				self.queueDelegate!.forceReload()
			}
		}
		
		let playlistObserver = NotificationCenter.default.addObserver(forType: PlaylistNotification.self,
																	  object: playerController,
																	  queue: OperationQueue.main,
																	  using: playlistHandler)
		
		observers.append(playlistObserver)
	}
}

