import logging

from fireo.models import Model
from fireo.fields import TextField, BooleanField, DateTime, NumberField

from music.model.playlist import Playlist

from werkzeug.security import check_password_hash

logger = logging.getLogger(__name__)


class User(Model):
    class Meta:
        collection_name = 'spotify_users'

    username = TextField(required=True)
    password = TextField(required=True)
    email = TextField()
    type = TextField(default="user")

    last_login = DateTime()
    last_keygen = DateTime()
    last_refreshed = DateTime()
    locked = BooleanField(default=False, required=True)
    validated = BooleanField(default=True, required=True)

    spotify_linked = BooleanField(default=False, required=True)
    access_token = TextField()
    refresh_token = TextField()
    token_expiry = NumberField()

    lastfm_username = TextField()

    def check_password(self, password):
        return check_password_hash(self.password, password)

    def to_dict(self):
        to_return = super().to_dict()

        # remove unnecessary and sensitive fields
        to_return.pop('password', None)
        to_return.pop('access_token', None)
        to_return.pop('refresh_token', None)
        to_return.pop('token_expiry', None)
        to_return.pop('id', None)
        to_return.pop('key', None)

        return to_return

    def get_playlist(self, playlist_name: str, single_return=True, raise_error=True):
        """Get a user's playlist by name with smart case sensitivity

        Will return an exact match if possible, otherwise will return the first case-insensitive match

        Args:
            playlist_name (str): Subject playlist name
            single_return (bool, optional): Return the best match, otherwise return (<exact>, <all matches>). <exact> will be None if not found. Defaults to True.
            raise_error (bool, optional): Raise a NameError if nothing found. Defaults to True.

        Raises:
            NameError: If no matching playlists found

        Returns:
            Optional[Playlist] or (<exact>, <all matches>): Found user's playlists
        """

        smart_playlists = Playlist.collection.parent(self.key).fetch()

        exact_match = None
        matches = list()
        for playlist in smart_playlists:
            if playlist.name == playlist_name:
                exact_match = playlist
            if playlist.name.lower() == playlist_name.lower():
                matches.append(playlist)

        if len(matches) == 0:
            # NO PLAYLIST FOUND
            logger.critical(f'playlist not found {self.username} / {playlist_name}')
            if raise_error:
                raise NameError(f'Playlist {playlist_name} not found for {self.username}')
            else:
                return None

        if single_return:
            if exact_match:
                return exact_match
            else:
                return matches[0]
        else:
            return exact_match, matches

    def get_playlists(self):
        """Get all playlists for a user

        Returns:
            List[Playlist]: List of users playlists 
        """
        return Playlist.collection.parent(self.key).fetch()