# defined to emulate the session object from the tidal module, which is
# defined in the tidalapi part (we want to keep the qobuz api/ dir as
# much alone as possible.
from __future__ import print_function

import sys
import json
from upmplgmodels import (
    Artist,
    Album,
    Track,
    Playlist,
    SearchResult,
    Category,
    Genre,
    Model,
)
from upmplgutils import *
import hraapi
import urllib
import datetime
import traceback
import base64


class Session(object):
    def __init__(self):
        self.api = hraapi.HRAAPI()

    def login(self, username, password, lang):
        self.api.setlang(lang)
        data = self.api.user_login(username=username, password=password)
        if data:
            return True
        else:
            return False

    def isloggedin(self):
        return self.api.isloggedin()

    def get_categories(self):
        return list(map(_parse_category, self.api.getAllCategories()))

    def get_genres(self, parent=None):
        data = self.api.getAllGenres()
        return [_parse_genre(g) for g in data]

    def get_catg_albums(self, prefix):
        data = self.api.listCategoryContent(category=prefix)
        return [_parse_album(a) for a in data]

    def get_alluserplaylists(self):
        data = self.api.listAllUserPlaylists()
        if not data:
            return []
        return [_parse_playlist(p) for p in data]

    def get_user_playlist(self, id):
        data = self.api.getUserPlaylist(playlist_id=id)
        if not data:
            return []
        return [_parse_track(t) for t in data]

    def get_alluseralbums(self):
        data = self.api.listAllUserAlbums()
        if not data:
            return []
        return [_parse_album(p) for p in data]

    def get_allusertracks(self):
        data = self.api.listAllUserTracks()
        if not data:
            return []
        return [_parse_track(p) for p in data]

    def get_album_tracks(self, albid):
        data = self.api.getAlbumDetails(album_id=albid)
        if not data:
            return {}
        # Apart from the tracks array, sata contains a copy of the album
        # metadata. Parse it like an album.
        album = _parse_album(data)
        return [_parse_track(t, album) for t in data["tracks"]]

    def get_media_url(self, trackid):
        data = self.api.getTrackById(track_id=trackid)
        if not data or "url" not in data or data["url"] is None:
            uplog("get_media_url: no url for [%s]" % trackid)
            return None
        return data["url"]

    def get_editormoods(self):
        data = self.api.getAvailableMoods()
        return [_parse_album(a) for a in data]

    def get_editorgenres(self):
        data = self.api.getAvailableGenres()
        return [_parse_album(a) for a in data]

    def get_editorthemes(self):
        data = self.api.getAvailableThemes()
        return [_parse_album(a) for a in data]

    def get_alleditorplaylists(self):
        data = self.api.getAllEditorPlaylists()
        return [_parse_album(a) for a in data]

    def get_editor_playlist(self, id):
        data = self.api.getEditorPlaylist(id=id)
        if not data:
            return []
        album = _parse_album(data)
        return [_parse_track(t, album) for t in data["tracks"]]

    def get_playlist_tracks(self, plid):
        data = self.api.playlist_get(playlist_id=plid, extra="tracks")
        return [_parse_track(t) for t in data["tracks"]["items"]]

    def search(self, value):
        data = self.api.quickSearch(search=value)
        albums = []
        for key, value in data.items():
            value["id"] = key
            albums.append(value)
        return [_parse_album(a) for a in albums]

    def searchCategory(self, value, prefix):
        data = self.api.searchCategory(category=prefix, search=value)
        return [_parse_album(a) for a in data]


def encode_prefix(p):
    return base64.urlsafe_b64encode(p.encode("utf-8")).decode("utf-8")


def decode_prefix(p):
    return base64.urlsafe_b64decode(p.encode("utf-8")).decode("utf-8")


def _parse_category(data):
    return Category(
        id=encode_prefix(data["prefix"]), name=data["title"], iid=data["id"]
    )


def _parse_genre(data):
    return Genre(id=encode_prefix(data["prefix"]), name=data["title"], iid=data["id"])


def _parse_artist(json_obj):
    artist = Artist(id=json_obj["id"], name=json_obj["title"].encode())
    return artist


def _parse_album(data):
    # uplog(data)
    # uplog("-_"*30)

    kwargs = {"id": data["id"], "name": data["title"]}
    if "artist" in data:
        kwargs["artist"] = data["artist"]
    if "cover" in data:
        if isinstance(data["cover"], dict):
            for key in ("preview", "master", "thumbnail"):
                if key in data["cover"]:
                    kwargs["image"] = "https://" + data["cover"][key]["file_url"]
                    break
        else:
            kwargs["image"] = data["cover"]
    elif "playlistCover" in data:
        kwargs["image"] = data["playlistCover"]

    a = Album(**kwargs)
    return a


def _parse_track(data, albumarg=None):
    artist = Artist(name=data["artist"])

    kwargs = {
        "id": data["playlistAdd"],
        "name": data["title"],
        "duration": data["playtime"],
        "format": data["format"],
        "artist": artist,
        "available": True,
    }

    if "trackNumber" in data:
        kwargs["track_num"] = data["trackNumber"]
    else:
        kwargs["track_num"] = 0

    if albumarg:
        kwargs["album"] = albumarg
    elif "cover" in data and "album" in data:
        kwargs["album"] = Album(image=data["cover"], name=data["album"])

    # If track has own cover, use it (e.g. for multialbum playlists)
    if "cover" in data:
        kwargs["image"] = data["cover"]

    return Track(**kwargs)


def _parse_playlist(data, artist=None, artists=None):
    kwargs = {
        "id": data["playlist_id"],
        "name": data["playlist_title"],
        "num_tracks": data.get("count_track"),
        "duration": data.get("duration"),
    }
    return Playlist(**kwargs)
