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

import UIKit
import CocoaLumberjack

class SearchViewController: MusicLibraryBaseViewController {
	private struct Segues {
		static let dismiss = "dismiss"
		static let showSongs = "showSongs"
		static let showAlbums = "showAlbums"
	}
	
	private var titleView: SearchTitleView?
	private var isSearching: Bool = false
	private var displayHelper: MusicListDisplayHelper?
	private var artistsDelegate: ArtistsDataSourceDelegate?
	private var albumsDelegate: AlbumsDataSourceDelegate?
	private var genresDelegate: GenresDataSourceDelegate?
	private var songsDelegate: SongsDataSourceDelegate?
	private var allSongs = Set<MusicLibrarySong>()
	
	@IBOutlet private weak var noSearchCoverView: UIView?
}

// MARK: - Overridden Methods
extension SearchViewController {
    override func viewDidLoad() {
        assert(playerGroup != nil)
		hasSearchButton = false
        super.viewDidLoad()
		
		self.delegate = self
		
		let titleRect = CGRect(x: 0, y: 0, width: 400, height: 44)
		titleView = SearchTitleView(frame: titleRect)
		titleView?.searchBar.delegate = self
		titleView?.cancelButton.addTarget(self,action: #selector(cancelTapped(_:)), for: .touchUpInside)
		
		navigationItem.titleView = titleView
		
		noSearchCoverView?.alpha = 1.0

        createAllTheThings()
    }
	
	override func viewDidAppear(_ animated: Bool) {
		super.viewDidAppear(animated)
		titleView?.searchBar.becomeFirstResponder()
	}
	
	override func viewWillDisappear(_ animated: Bool) {
		super.viewWillDisappear(animated)
		if titleView!.searchBar.isFirstResponder {
			titleView?.searchBar.resignFirstResponder()
		}
	}
	
	override func viewWillLayoutSubviews() {
		super.viewWillLayoutSubviews()

		let titleRect = CGRect(x: 0, y: 0, width: view.frame.width, height: 44)
		titleView?.frame = titleRect
		
		navigationItem.titleView = titleView
	}
	
	override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
		if titleView!.searchBar.isFirstResponder {
			titleView?.searchBar.resignFirstResponder()
		}
		if let albumVC = segue.destination as? AlbumsViewController {
			// Need to show albums in selection.. but from where
			var albums = [MusicLibraryAlbum]()
			if let genre = sender as? MusicLibraryGenre {
				albums = LocalMusicLibrary.sharedInstance.albumsForGenre(genre)
			} else if let artist = sender as? MusicLibraryArtist {
				albums = LocalMusicLibrary.sharedInstance.albumsForArtist(artist)
			}
			albumVC.selectedAlbums = albums
			albumVC.injectDependencies(preferences: preferences, playerController: playerController)
			albumVC.playerGroup = playerGroup
		}
		if let songsVC = segue.destination as? SongsViewController {
			var songs = [MusicLibrarySong] ()
			if let album = sender as? MusicLibraryAlbum {
				songs = LocalMusicLibrary.sharedInstance.songsForAlbum(album)
			}
			songsVC.selectedSongs = songs
			songsVC.injectDependencies(preferences: preferences, playerController: playerController)
			songsVC.playerGroup = playerGroup
		}
	}
}

// MARK: - UI Actions
extension SearchViewController {
	@objc private func cancelTapped(_ sender: UIButton) {
		performSegue(withIdentifier: Segues.dismiss, sender: self)
	}
}

// MARK: - MusicLibraryViewControllerDelegate Conformance
extension SearchViewController: MusicLibraryViewControllerDelegate {
	func allMediaItems() -> [IoTMediaItem] {
		return allSongs.compactMap { LocalMusicLibrary.sharedInstance.mediaItemForSong($0) }
	}
	
	func optionsForButton() -> [String] {
		let options = [MusicLibraryOptions.playNow.toString(),
					   MusicLibraryOptions.playNext.toString(),
					   MusicLibraryOptions.addToQueue.toString()]
		return options
	}
	
	func doOption(_ option: MusicLibraryOptions) -> Bool {
		return false
	}
}

// MARK: - UISearchBarDelegate Conformance
extension SearchViewController: UISearchBarDelegate {
	func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
		if searchText.count == 0 {
			artistsDelegate?.forceReload(artists: [])
			albumsDelegate?.forceReload(albums: [])
			genresDelegate?.forceReload(genres: [])
			songsDelegate?.forceReload(songs: [])
			allSongs = Set()
			noSearchCoverView?.alpha = 1.0
		} else {
			DispatchQueue.main.async { [weak self] in
				guard let self = self else { return }
				let (artists, artistSongs) = LocalMusicLibrary.sharedInstance.allArtists(searchString: searchText)
				self.artistsDelegate?.forceReload(artists: artists)
				
				let (albums, albumSongs) = LocalMusicLibrary.sharedInstance.allAlbums(searchString: searchText)
				self.albumsDelegate?.forceReload(albums: albums)
				
				let (genres, genreSongs) = LocalMusicLibrary.sharedInstance.allGenres(searchString: searchText)
				self.genresDelegate?.forceReload(genres: genres)
				
				let songs = LocalMusicLibrary.sharedInstance.allSongs(searchString: searchText)
				self.songsDelegate?.forceReload(songs: songs)
				
				self.allSongs = Set(songs).union(artistSongs).union(albumSongs).union(genreSongs)
				self.updatePlayAllButtonText(count: self.allSongs.count)
				self.noSearchCoverView?.alpha = 0.0
			}
		}
	}
	
	func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
		titleView?.cancelButton.setTitle(NSLocalizedString("CANCEL", comment: "Cancel"), for: .normal)
		titleView?.cancelButton.setTitle(NSLocalizedString("CANCEL", comment: "Cancel"), for: .highlighted)
		titleView?.cancelButton.setTitle(NSLocalizedString("CANCEL", comment: "Cancel"), for: .selected)
	}
	
	func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
		titleView?.cancelButton.setTitle(NSLocalizedString("DONE", comment: "Cancel"), for: .normal)
		titleView?.cancelButton.setTitle(NSLocalizedString("DONE", comment: "Cancel"), for: .highlighted)
		titleView?.cancelButton.setTitle(NSLocalizedString("DONE", comment: "Cancel"), for: .selected)
		
		if titleView!.searchBar.isFirstResponder {
			titleView?.searchBar.resignFirstResponder()
		}
	}
}

// MARK: - Private Methods
extension SearchViewController {
	override func handleLibraryInvalidation() {
		if let sb = titleView?.searchBar {
			searchBar(sb, textDidChange: sb.text ?? "")
		}
	}

	private func createAllTheThings() {
		var dataSources: [MusicListDataSource] = []
		
		artistsDelegate = ArtistsDataSourceDelegate(artists: [])
		let artistsDataSource = MusicListDataSource(playerGroup: playerGroup!,
													playerController: playerController,
													delegate: artistsDelegate!)
		artistsDataSource.sectionIndex = dataSources.count
		dataSources.append(artistsDataSource)
		
		// *********
		
		albumsDelegate = AlbumsDataSourceDelegate(albums: [])
		let albumsDataSource = MusicListDataSource(playerGroup: playerGroup!,
												   playerController: playerController,
												   delegate: albumsDelegate!)
		albumsDataSource.sectionIndex = dataSources.count
		dataSources.append(albumsDataSource)
		
		// *********
		
		genresDelegate = GenresDataSourceDelegate(genres: [])
		let genresDataSource = MusicListDataSource(playerGroup: playerGroup!,
												   playerController: playerController,
												   delegate: genresDelegate!)
		genresDataSource.sectionIndex = dataSources.count
		dataSources.append(genresDataSource)
		
		// *********
		
		songsDelegate = SongsDataSourceDelegate(songs: [])
		let songsDataSource = MusicListDataSource(playerGroup: playerGroup!,
												  playerController: playerController,
												  delegate: songsDelegate!)
		songsDataSource.sectionIndex = dataSources.count
		dataSources.append(songsDataSource)
		
		displayHelper = MusicListDisplayHelper(dataSources: dataSources,
											   viewController: self,
											   collectionView: collectionView!,
											   dragAllowed: false,
											   countUpdater: nil,
											   onItemSelected: { [weak self] indexPath, item in
												guard let self = self else {
													return
												}
												self.didSelect(indexPath: indexPath, item: item)
												
		})
	}
	
	private func didSelect(indexPath: IndexPath, item: MusicListDisplayHelperItem) {
		switch indexPath.section {
		case 0:
			// Artists
			if let chosenArtist = artistsDelegate?.artists[indexPath.row] {
				performSegue(withIdentifier: Segues.showAlbums, sender: chosenArtist)
			}
		case 1:
			// Albums
			if let chosenAlbum = albumsDelegate?.albums[indexPath.row] {
				performSegue(withIdentifier: Segues.showSongs, sender: chosenAlbum)
			}
		case 2:
			// Genres
			if let chosenGenre = genresDelegate?.genres[indexPath.row] {
				performSegue(withIdentifier: Segues.showAlbums, sender: chosenGenre)
			}
		case 3:
			// Songs
			guard let chosenSong = songsDelegate?.songs[indexPath.row],
				let mediaItem = LocalMusicLibrary.sharedInstance.mediaItemForSong(chosenSong),
				let playlist = playerGroup?.playlist else {
					return
			}
			QueueOperationsHelper.sharedInstance.add(toPlaylist: playlist,
													 item: mediaItem,
													 atEnd: true,
													 playNow: true,
													 completion: nil,
													 completionQueue: nil)
		default:
			break
		}
	}
}
