import os
import libsonic

from pushtunes.utils.logging import get_logger


class SubsonicClient:
    """Client for interacting with Subsonic music server"""

    def __init__(
        self,
        url: str | None = None,
        username: str | None = None,
        password: str | None = None,
        port: int = 443,
    ):
        """Initialize Subsonic client with connection parameters

        Args:
            url: Subsonic server URL (defaults to SUBSONIC_URL env var)
            username: Username (defaults to SUBSONIC_USER env var)
            password: Password (defaults to SUBSONIC_PASS env var)
            port: Server port (defaults to 443)
        """
        self.url: str | None = url or os.getenv("SUBSONIC_URL")
        self.username: str | None = username or os.getenv("SUBSONIC_USER")
        self.password: str | None = password or os.getenv("SUBSONIC_PASS")
        self.port: int = port

        self.connection: libsonic.Connection = libsonic.Connection(
            self.url, self.username, self.password, port=self.port
        )

        self.log = get_logger()

    def get_albums(self, albums=None, offset=0):
        """Fetch all albums from Subsonic server

        Args:
            albums: Existing list of albums to append to (for recursion)
            offset: Pagination offset

        Returns:
            List of album dictionaries with 'artist' and 'title' keys
        """
        if albums is None:
            albums = []

        albumlist = self.connection.getAlbumList2(
            "alphabeticalByArtist", size=500, offset=offset
        )
        albumentries = albumlist["albumList2"]["album"]

        for entry in albumentries:
            self.log.info(
                f"Fetching Subsonic metadata for {entry.get('artist', 'Unknown')} - {entry.get('name', 'Unknown')}"
            )
            if not (
                entry["name"] == "[Unknown Album]"
                or entry["artist"] == "[Unknown Artist]"
            ):
                album_id = entry["id"]
                album_year = None
                try:
                    # Fetch full album details to get the year
                    album_details = self.connection.getAlbum(album_id)
                    if "album" in album_details and "song" in album_details["album"]:
                        # Take the year from the first song
                        first_song = album_details["album"]["song"][0]
                        if "year" in first_song:
                            album_year = int(first_song["year"])
                except Exception as e:
                    self.log.warning(
                        f"Could not fetch year for album {entry['name']}: {e}"
                    )

                albums.append(
                    {
                        "artist": entry["artist"],
                        "title": entry["name"],
                        "year": album_year,
                    }
                )

        if len(albumentries) == 500:
            # Make a recursive call without passing the albums list to prevent duplication
            additional_albums = self.get_albums(None, offset + 500)
            albums.extend(additional_albums)

        return albums

    def get_tracks(self, tracks=None, offset=0):
        """Fetch all starred/favorite tracks from Subsonic server

        Args:
            tracks: Existing list of tracks to append to (for recursion)
            offset: Pagination offset

        Returns:
            List of track dictionaries with 'artist', 'title', 'album', 'year' keys
        """
        if tracks is None:
            tracks = []

        starred = self.connection.getStarred2()
        if "starred2" not in starred or "song" not in starred["starred2"]:
            return tracks

        song_entries = starred["starred2"]["song"]

        for entry in song_entries:
            self.log.info(
                f"Fetching Subsonic metadata for {entry.get('artist', 'Unknown')} - {entry.get('title', 'Unknown')}"
            )

            # Skip unknown tracks
            if (
                entry.get("title") == "[Unknown]"
                or entry.get("artist") == "[Unknown Artist]"
            ):
                continue

            track_year = None
            if "year" in entry:
                try:
                    track_year = int(entry["year"])
                except (ValueError, TypeError):
                    pass

            tracks.append(
                {
                    "artist": entry.get("artist", ""),
                    "title": entry.get("title", ""),
                    "album": entry.get("album"),
                    "year": track_year,
                }
            )

        return tracks

    def get_playlists(self):
        """Fetch all playlists from Subsonic server

        Returns:
            List of playlist dictionaries with 'id' and 'name' keys
        """
        result = self.connection.getPlaylists()
        if "playlists" not in result or "playlist" not in result["playlists"]:
            return []

        playlists = result["playlists"]["playlist"]
        # Handle case where there's only one playlist (returns dict instead of list)
        if isinstance(playlists, dict):
            playlists = [playlists]

        return playlists

    def get_playlist(self, playlist_id):
        """Fetch a specific playlist by ID

        Args:
            playlist_id: ID of the playlist to fetch

        Returns:
            Playlist dictionary with 'name' and 'entry' keys
        """
        result = self.connection.getPlaylist(playlist_id)
        if "playlist" not in result:
            return None

        playlist = result["playlist"]

        # Handle case where there are no entries in the playlist
        if "entry" not in playlist:
            playlist["entry"] = []
        # Handle case where there's only one entry (returns dict instead of list)
        elif isinstance(playlist["entry"], dict):
            playlist["entry"] = [playlist["entry"]]

        return playlist
