import xmltodict
import json
import xmltodict
import json
import re

from src.Library import *

class XmlToJson:
    def flatten_dict(self, d):

        out = []
        for song in d:
            newSong = {}

            strCount = 0
            intCount = 0
            dateCount = 0

            def getStr(id):
                nonlocal strCount
                if id not in song["key"]:
                    return "undef"
                if len(song["string"]) <= strCount:
                    return "error"
                strCount += 1
                return song["string"][strCount - 1]

            def getInt(id):
                nonlocal intCount
                if id not in song["key"]:
                    return -1
                if len(song["integer"]) <= intCount:
                    return -1
                intCount += 1
                return song["integer"][intCount - 1]

            def getDate(id):
                nonlocal dateCount
                if id not in song["key"]:
                    return "undef"
                if len(song["date"]) <= dateCount:
                    return "error"
                dateCount += 1
                return song["date"][dateCount - 1]

            newSong["Track ID"] = getInt("Track ID")
            newSong["Name"] = getStr("Name")
            newSong["Artist"] = getStr("Artist")
            newSong["Album Artist"] = getStr("Album Artist")
            newSong["Composer"] = getStr("Composer")
            newSong["Album"] = getStr("Album")
            newSong["Genre"] = getStr("Genre")
            newSong["Kind"] = getStr("Kind")
            newSong["Size"] = getInt("Size")
            newSong["Total Time"] = getInt("Total Time")
            newSong["Disc Number"] = getInt("Disc Number")
            newSong["Disc Count"] = getInt("Disc Count")
            newSong["Track Number"] = getInt("Track Number")
            newSong["Track Count"] = getInt("Track Count")
            newSong["Year"] = getInt("Year")
            newSong["Date Modified"] = getDate("Date Modified")
            newSong["Date Added"] = getDate("Date Added")
            newSong["Bit Rate"] = getInt("Bit Rate")
            newSong["Sample Rate"] = getInt("Sample Rate")
            newSong["Play Count"] = getInt("Play Count")
            newSong["Play Date"] = getInt("Play Date")
            newSong["Play Date UTC"] = getDate("Play Date UTC")
            newSong["Skip Count"] = getInt("Skip Count")
            newSong["Skip Date"] = getDate("Skip Date")
            newSong["Release Date"] = getDate("Release Date")
            newSong["Album Rating"] = getInt("Album Rating")
            newSong["Album Rating Computed"] = "Album Rating Computed" in song["key"]
            newSong["Loved"] = "Loved" in song["key"]
            newSong["Album Loved"] = "Album Loved" in song["key"]
            newSong["Explicit"] = "Explicit" in song["key"]
            newSong["Compilation"] = "Compilation" in song["key"]
            newSong["Artwork Count"] = getInt("Artwork Count")
            newSong["Sort Album"] = getStr("Sort Album")
            newSong["Sort Artist"] = getStr("Sort Artist")
            newSong["Sort Name"] = getStr("Sort Name")
            newSong["Persistent ID"] = getStr("Persistent ID")
            newSong["Track Type"] = getStr("Track Type")

            out.append(newSong)

        return out


    def convert(self, filename, out_path):
        with open(filename, 'r', encoding='utf-8') as xml_file:
            data_dict = xmltodict.parse(xml_file.read())

        # Extract the "Tracks" dictionary to be flattened
        tracks_dict = data_dict['plist']['dict']['dict']

        flat_tracks_dict = self.flatten_dict(tracks_dict["dict"])

        json_data = json.dumps(flat_tracks_dict, indent=2)

        with open(out_path, 'w', encoding='utf-8') as json_file:
            json_file.write(json_data)


class ParseItunesXml:
    def __init__(self):
        self.track_map: dict[str, Track] = {}
        self.artist_map: dict[str, Artist] = {}
        self.album_map: dict[str, Album] = {}
        self.library = Library()


    def parse_artists(self, data: list) -> List[Artist]:
        if not data:
            raise "No artist found"

        artists = []

        for artist_data in data:
            name = artist_data
            artist_id = name

            if artist_id in self.artist_map:
                artists.append(self.artist_map[artist_id])
                continue

            artist = Artist()
            artist.id = artist_id
            artist.title = name

            self.artist_map[artist_id] = artist
            self.library.artists.append(artist)

            artists.append(artist)

        return artists

    def parse_album(self, data: str) -> Album:
        if not data:
            raise "album is none"

        name = data
        album_id = name

        if album_id in self.album_map:
            return self.album_map[album_id]

        album = Album()
        album.id = album_id
        album.title = name

        self.album_map[album_id] = album
        self.library.albums.append(album)

        return album


    def parse(self, tracks_file_xml: Path, tracks_file_json: Path) -> Library:
        XmlToJson().convert(tracks_file_xml, tracks_file_json)

        tracks_content = json.loads(tracks_file_json.read_text())

        for data in tracks_content:
            track = Track()

            track.id = data.get("Track ID")
            track.title = data.get("Name")
            track.artists = self.parse_artists([data.get("Artist")])
            track.album = self.parse_album(data.get("Album"))
            track.play_count = int(data.get("Play Count"))

            if not track.album or not len(track.artists) or not track.title:
                raise "error parsing"

            self.track_map[track.id] = track
            self.library.tracks.append(track)

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

        self.library.update_cache()

        self.library.name = "Itunes"

        for track in self.library.tracks:
            track.auto_score = track.play_count

        return self.library


