__all__ = ["LastFm", "LastFmException"]

import os
from dataclasses import asdict
from pprint import pprint
from typing import Optional

import requests
from dotenv import load_dotenv

from yutipy.exceptions import LastFmException
from yutipy.logger import logger
from yutipy.models import UserPlaying
from yutipy.utils.helpers import separate_artists

load_dotenv()

LASTFM_API_KEY = os.getenv("LASTFM_API_KEY")


class LastFm:
    """
    A class to interact with the Last.fm API for fetching user music data.

    This class reads the ``LASTFM_API_KEY`` from environment variables or the ``.env`` file by default.
    Alternatively, you can manually provide this values when creating an object.
    """

    def __init__(self, api_key: str = None):
        """
        Initializes the LastFm class.

        Args:
            lastfm_api_key (str, optional): The Last.fm API key. If not provided,
                it will be fetched from the environment variable `LASTFM_API_KEY`.

        Parameters
        ----------
        lastfm_api_key : str, optional
            The Lastfm API Key (<https://www.last.fm/api>). Defaults to ``LASTFM_API_KEY`` from environment variable or the ``.env`` file.

        Raises:
            LastFmException: If the API key is not provided or found in the environment.
        """
        self.api_key = api_key or LASTFM_API_KEY

        if not self.api_key:
            raise LastFmException(
                "Lastfm API key was not found. Set it in environment variable or directly pass it when creating object."
            )

        self._is_session_closed = False

        self.__api_url = "https://ws.audioscrobbler.com/2.0"
        self.__session = requests.Session()

    def __enter__(self):
        """Enters the runtime context related to this object."""
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        """Exits the runtime context related to this object."""
        self.close_session()

    def close_session(self) -> None:
        """Closes the current session(s)."""
        if not self._is_session_closed:
            self.__session.close()
            self._is_session_closed = True

    @property
    def is_session_closed(self) -> bool:
        """Checks if the session is closed."""
        return self._is_session_closed

    def get_currently_playing(self, username: str) -> Optional[UserPlaying]:
        """
        Fetches information about the currently playing or most recent track for a user.

        Parameters
        ----------
        username : str
            The Last.fm username to fetch data for.

        Returns
        -------
        Optional[UserPlaying_]
            An instance of the ``UserPlaying`` model containing details about the currently
            playing track if available, or ``None`` if the request fails or no data is available.
        """
        query = f"?method=user.getrecenttracks&user={username}&limit=1&api_key={self.api_key}&format=json"
        query_url = self.__api_url + query

        try:
            response = self.__session.get(query_url, timeout=30)
            response.raise_for_status()
        except requests.RequestException as e:
            logger.error(f"Failed to fetch user profile: {e}")
            return None

        response_json = response.json()
        result = response_json.get("recenttracks", {}).get("track", [])[0]
        album_art = [
            img.get("#text")
            for img in result.get("image", [])
            if img.get("size") == "extralarge"
        ]
        return UserPlaying(
            album_art="".join(album_art),
            album_title=result.get("album", {}).get("#text"),
            artists=", ".join(separate_artists(result.get("artist", {}).get("#text"))),
            id=result.get("mbid"),
            title=result.get("name"),
            url=result.get("url"),
            is_playing=result.get("@attr", {}).get("nowplaying", False),
        )


if __name__ == "__main__":
    with LastFm() as lastfm:
        username = input("Enter Lasfm Username: ").strip()
        result = lastfm.get_currently_playing(username=username, limit=5)

        if result:
            pprint(asdict(result))
        else:
            print("No result was found. Make sure the username is correct!")
