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

import Foundation

struct PersistedAllUserPlaylists: Codable {
    var playlists: [UUID : PersistedUserPlaylist] = [:]
}

// MARK: -

struct PersistedUserPlaylist: Codable {
    var id: UUID
    var name: String
    var items: [PersistedMediaItem]
    
    func userPlaylist() -> UserPlaylist {
        let userPlaylist = UserPlaylist(id: id)
        userPlaylist.name = name
        userPlaylist.items = []
        items.forEach {
            if let mediaItem = $0.mediaItem() {
                userPlaylist.items.append(mediaItem)
            }
        }
        return userPlaylist
    }
    
    init() {
        id = UUID ()
        name = ""
        items = []
    }
    
    init (userPlaylist: UserPlaylist) {
        id = userPlaylist.id
        name = userPlaylist.name
        items = userPlaylist.items.map { PersistedMediaItem(item: $0) }
    }
}

// MARK: -

enum UserPlaylistsControllerError: Error {
	case nameExists
}

// MARK: -

class UserPlaylistsController {
    public static let sharedInstance = UserPlaylistsController()
    
    private lazy var storedObject: PersistedAllUserPlaylists = {
        guard let i: PersistedAllUserPlaylists = PersistenceController.load() else {
            return PersistedAllUserPlaylists()
        }
        return i
    } ()
}

// MARK: - Public Methods
extension UserPlaylistsController {
    public func haveUserPlaylists() -> Bool {
        return storedObject.playlists.count != 0
    }
    
    public func createUserPlaylist() -> UserPlaylist {
        let persistedPlaylist = PersistedUserPlaylist()
        storedObject.playlists[persistedPlaylist.id] = persistedPlaylist
        PersistenceController.store(storedObject)
        return persistedPlaylist.userPlaylist()
    }
	
	public func createUserPlaylist(name: String, items: [IoTMediaItem]) throws -> UserPlaylist? {
		if playlistExists(forName: name) {
			throw UserPlaylistsControllerError.nameExists
		}
		
		let playlist = createUserPlaylist()
		playlist.name = name
		playlist.items = items
		updateUserPlaylist(playlist)
		return playlist
	}
    
    public func removeUserPlaylist(_ playlist: UserPlaylist) {
        storedObject.playlists[playlist.id] = nil
        PersistenceController.store(storedObject)
    }
    
    public func allUserPlaylists() -> [UserPlaylist] {
        let sortedPlaylists = storedObject.playlists.values.sorted { $0.name < $1.name }
        let userPlaylists = sortedPlaylists.map { $0.userPlaylist() }
        return userPlaylists
    }
	
	public func playlistExists(forName name: String) -> Bool {
		let all = storedObject.playlists.values
		return all.contains { $0.name == name }
	}
    
    public func updateUserPlaylist(_ playlist: UserPlaylist) {
        let persisted = PersistedUserPlaylist(userPlaylist: playlist)
        storedObject.playlists[persisted.id] = persisted
        PersistenceController.store(storedObject)
    }
}
