from __future__ import annotations

from datetime import datetime
from pathlib import Path
from typing import List, Optional, Any


class Entity:
    def __init__(self):
        self.id: str = None
        self.mbid: str = None

        self.title: str = None
        self.duration_ms: int = None

        self.fav: bool = False
        self.rating: int = 0
        self.play_count: int = 0
        self.date_added: datetime = None
        self.date_released: datetime = None
        self.date_last_play: datetime = None
        self.auto_score: float = 0

        self.local_id: str = None
        self.local_path: Path = None
        self.resolved_percentage: float = 0


class Artist(Entity):
    def __init__(self):
        super().__init__()
        self.tracks: List[Track] = []
        self.albums: List[Album] = []


class Track(Entity):
    def __init__(self):
        super().__init__()

        self.artists: List[Artist] = []
        self.album: Album = None

        self.has_lyrics: bool = False


class Album(Entity):
    def __init__(self):
        super().__init__()
        self.tracks: List[Track] = []
        self.artists: List[Artist] = []


class Playlist(Entity):
    def __init__(self):
        super().__init__()
        self.tracks: List[Track] = []
        self.created_at: datetime = None
        self.description: str = None


class Library:
    def __init__(self):
        self.artists: List[Artist] = []
        self.playlists: List[Playlist] = []
        self.tracks: List[Track] = []
        self.albums: List[Album] = []

        self.liked_tracks: List[Track] = []
        self.top_tracks: List[Track] = []
        self.top_artists: List[Artist] = []

        self.artist_map: dict[str, Artist] = None
        self.album_map: dict[str, Album] = None
        self.track_map: dict[str, Track] = None

        self.name = "Unnamed"

    def update_cache(self):
        self.update_id_maps()
        self.create_reverse_links()
        self.score_albums()
        self.calc_resolved_percentage()

    def update_id_maps(self):
        self.artist_map: dict[str, Artist] = {artist.id: artist for artist in self.artists}
        self.album_map: dict[str, Album] = {album.id: album for album in self.albums}
        self.track_map: dict[str, Track] = {track.id: track for track in self.tracks}

    def create_reverse_links(self):
        for track_id, track in self.track_map.items():
            for artist in track.artists:
                if track not in artist.tracks:
                    artist.tracks.append(track)

            if track not in track.album.tracks:
                track.album.tracks.append(track)

        for album_id, album in self.album_map.items():
            for artist in album.artists:
                if album not in artist.albums:
                    artist.albums.append(album)

    def auto_score(self):
        self.score_albums()
        self.score_artists()

    def score_artists(self):
        for track in self.tracks:
            for artist in track.artists:
                artist.auto_score += track.auto_score

    def score_albums(self):
        for track in self.tracks:
            track.album.auto_score += track.auto_score

    def calc_resolved_percentage(self):
        for artist in self.artists:
            artist_count_resolved = 0
            artist_count = 0
            for album in artist.albums:
                album_count_resolved = 0
                for track in album.tracks:
                    if track.local_id:
                        album_count_resolved += 1
                album.resolved_percentage = album_count_resolved / len(album.tracks)
                artist_count_resolved += album_count_resolved
                artist_count += len(album.tracks)
            artist.resolved_percentage = artist_count_resolved / artist_count
