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

import UIKit
import CocoaLumberjack

protocol MiniPlayerEmbedding {
    func embedMiniPlayer(_ miniPlayer: MiniPlayerViewController)
    func removeMiniPlayer()

    func handlePlaylistNotification(_ notification: PlaylistNotification)
    func handlePlayerGroupNotification(_ notification: PlayerGroupNotification)
}

// MARK: -

class MiniPlayerEmbeddingViewController: UIViewController, MiniPlayerEmbedding {
    // MARK: Public Properties
    var playerGroup: IoTPlayerGroup?
    weak var miniPlayerController: MiniPlayerViewController?
    private var playlistObserver: ObserverToken?
    private var playerGroupObserver: ObserverToken?
    var hasSearchButton: Bool = true
    var inSearchMode: Bool = false

    // MARK: Outlets
    @IBOutlet private weak var miniPlayerContainer: UIView?
    @IBOutlet private weak var miniPlayerContainerHeightConstraint: NSLayoutConstraint?

    // Methods that may need to be overridden. We could define them as @objc but that's a bit meh.

    func handlePlaylistNotification(_ notification: PlaylistNotification) {
        guard notification.playlist == playerGroup?.playlist else {
            return
        }
        updateMiniPlayer()
    }

    func handlePlayerGroupNotification(_ notification: PlayerGroupNotification) {
        guard let group = playerGroup,
            notification.playerGroup == group  else {
                return

        }

        if notification.reason == .removed {
            // We've been deleted!!!
            playerGroup = nil
            updateMiniPlayer()
            updateUI()
        }
        
        if notification.reason == .playStateChanged ||
            notification.reason == .inputSelectorChanged {
            updateMiniPlayer()
        }
    }

    deinit {
        if let observer = playlistObserver {
            NotificationCenter.default.removeObserver(observer)
            playlistObserver = nil
        }
        if let observer = playerGroupObserver {
            NotificationCenter.default.removeObserver(observer)
            playerGroupObserver = nil
        }
    }
}

// MARK: - Overridden Methods
extension MiniPlayerEmbeddingViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if hasSearchButton {
            if let searchImage = UIImage(named: "btn-search"),
                let searchImagePressed = UIImage(named: "btn-search-pressed") {
                let resizableSearch = searchImage.resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: searchImage.size.width-1))
                let resizableSearchImagePressed = searchImagePressed.resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: searchImagePressed.size.width-1))
                let rightBarButton = UIBarButtonItem(title: " ", style: .plain, target: self, action: #selector(didTapSearch(_:)))
                rightBarButton.setBackgroundImage(resizableSearch, for: .normal, barMetrics: .default)
                rightBarButton.setBackgroundImage(resizableSearchImagePressed, for: .highlighted, barMetrics: .default)
                rightBarButton.makeAccessible(Accessibility.MediaLibrary.navBarSearchButton)
                navigationItem.rightBarButtonItem = rightBarButton
            }
        }
        
        miniPlayerContainerHeightConstraint?.constant = 0

        // Observers are added during viewDidLoad rather than viewWIllAppear as satcked views need to respond to what happens above them.

        if playlistObserver == nil {
            let playlistHandler: (PlaylistNotification) -> () = { [weak self] notification in
                guard let self = self else { return }
                self.handlePlaylistNotification(notification)
            }

            playlistObserver = NotificationCenter.default.addObserver(forType: PlaylistNotification.self,
                                                                      object: playerController,
                                                                      queue: OperationQueue.main,
                                                                      using: playlistHandler)
        }

        if playerGroupObserver == nil {
            let playerGroupHandler: (PlayerGroupNotification) -> () = { [weak self] notification in
                guard let self = self else {
                    return
                }

                self.handlePlayerGroupNotification(notification)
            }

            playerGroupObserver = NotificationCenter.default.addObserver(forType: PlayerGroupNotification.self,
                                                                         object: playerController,
                                                                         queue: OperationQueue.main,
                                                                         using: playerGroupHandler)
        }

    }

    @objc func updateUI() {
    }
}

// MARK:- Public Methods
extension MiniPlayerEmbeddingViewController {
	func updateMiniPlayer() {
		guard let miniPlayer = miniPlayerController else {
			return
		}
		var playableOrPlaying = true
        if
            let pg = playerGroup,
            let selector = pg.activeInputSelector {
            let btOrPlaylist = selector.type == .bluetooth || selector.type == .none
            if btOrPlaylist {
                let item = playerGroup?.playlist?.currentItem
                if item == nil || item!.isEmpty {
                    if selector.type == .bluetooth || (playerGroup?.playlist?.count ?? 0) == 0 {
                        // We still show the miniplayer if there are items in the playlist.
                    	playableOrPlaying = false
                    }
                }
            }
        } else {
            playableOrPlaying = false
        }

		DDLogVerbose("**** updateMiniPlayer - playing or playable: \(playableOrPlaying)")
		
		let height = playableOrPlaying ? MiniPlayerViewController.expandedLayoutHeight : 0
		miniPlayer.view.isHidden = !playableOrPlaying
		
		miniPlayerContainerHeightConstraint?.constant = height
	}
	
	func embedMiniPlayer(_ miniPlayer: MiniPlayerViewController) {
        if miniPlayer.containerViewController == self {
            return
        }
		miniPlayerController = miniPlayer
		miniPlayerController?.containerViewController = self
		
		updateMiniPlayer()
		miniPlayerContainer?.addSubview(miniPlayer.view)

        miniPlayer.view.frame = miniPlayerContainer!.bounds
        miniPlayer.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
	}
	
	func removeMiniPlayer() {
		miniPlayerController?.view.removeFromSuperview()
		miniPlayerController = nil
        miniPlayerContainerHeightConstraint?.constant = 0
	}

	@IBAction func unwindNowPlayingOrQueue(segue: UIStoryboardSegue) {
		// DO NOT REMOVE
	}
}

// MARK: - Private Methods
extension MiniPlayerEmbeddingViewController {
	@objc private func didTapSearch(_ sender: AnyObject?) {
		// Are we in search mode
		if let searchController = navigationController as? SearchNavigationController {
			// If we are just pop to root
			searchController.popToRootViewController(animated: true)
		} else {
			// Else we need to go into search mode.
			let searchNavController = SearchNavigationController.instantiateFromStoryboard(name: "Music")
			searchNavController.playerGroup = playerGroup
			searchNavController.injectDependencies(preferences: preferences, playerController: playerController)
			searchNavController.modalTransitionStyle = .crossDissolve
			searchNavController.modalPresentationStyle = .overCurrentContext
			if let searchVC = searchNavController.topViewController as? SearchViewController {
				searchVC.playerGroup = playerGroup
				searchVC.injectDependencies(preferences: preferences, playerController: playerController)
			}
			present(searchNavController, animated: true, completion: nil)
		}
	}
	
	@IBAction func returnFromSearch(segue: UIStoryboardSegue) {
		// Do not remove
	}
}

