import re
from os.path import sep as pathSep
from pathlib import Path
from unicodedata import normalize
from deemix.api.deezer import TrackFormats

bitrateLabels = {
    TrackFormats.MP4_RA3: "360 HQ",
    TrackFormats.MP4_RA2: "360 MQ",
    TrackFormats.MP4_RA1: "360 LQ",
    TrackFormats.FLAC   : "FLAC",
    TrackFormats.MP3_320: "320",
    TrackFormats.MP3_128: "128",
    TrackFormats.DEFAULT: "128",
    TrackFormats.LOCAL  : "MP3"
}

def fixName(txt, char='_'):
    txt = str(txt)
    txt = re.sub(r'[\0\/\\:*?"<>|]', char, txt)
    txt = normalize("NFC", txt)
    return txt

def fixEndOfData(bString):
    try:
        bString.decode()
        return True
    except:
        return False

def fixLongName(name):
    if pathSep in name:
        sepName = name.split(pathSep)
        name = ""
        for txt in sepName:
            txt = fixLongName(txt)
            name += txt + pathSep
        name = name[:-1]
    else:
        name = name.encode('utf-8')[:200]
        while not fixEndOfData(name):
            name = name[:-1]
        name = name.decode()
    return name


def antiDot(string):
    while string[-1:] == "." or string[-1:] == " " or string[-1:] == "\n":
        string = string[:-1]
    if len(string) < 1:
        string = "dot"
    return string


def pad(num, max, settings):
    if int(settings['paddingSize']) == 0:
        paddingSize = len(str(max))
    else:
        paddingSize = len(str(10 ** (int(settings['paddingSize']) - 1)))
    if paddingSize == 1:
        paddingSize = 2
    if settings['padTracks']:
        return str(num).zfill(paddingSize)
    else:
        return str(num)

def generateFilename(track, settings, template):
    filename = template or "%artist% - %title%"
    return settingsRegex(filename, track, settings)

def generateFilepath(track, settings):
    filepath = Path(settings['downloadLocation'])
    artistPath = None
    coverPath = None
    extrasPath = None

    if settings['createPlaylistFolder'] and track.playlist and not settings['tags']['savePlaylistAsCompilation']:
        filepath = filepath / settingsRegexPlaylist(settings['playlistNameTemplate'], track.playlist, settings)

    if track.playlist and not settings['tags']['savePlaylistAsCompilation']:
        extrasPath = filepath

    if (
        (settings['createArtistFolder'] and not track.playlist) or
        (settings['createArtistFolder'] and track.playlist and settings['tags']['savePlaylistAsCompilation']) or
        (settings['createArtistFolder'] and track.playlist and settings['createStructurePlaylist'])
    ):
        filepath = filepath / settingsRegexArtist(settings['artistNameTemplate'], track.album['mainArtist'], settings)
        artistPath = filepath

    if (settings['createAlbumFolder'] and
            (not track.singleDownload or (track.singleDownload and settings['createSingleFolder'])) and
            (not track.playlist or
                (track.playlist and settings['tags']['savePlaylistAsCompilation']) or
                (track.playlist and settings['createStructurePlaylist'])
            )
    ):
        filepath = filepath / settingsRegexAlbum(settings['albumNameTemplate'], track.album, settings, track.playlist)
        coverPath = filepath

    if not (track.playlist and not settings['tags']['savePlaylistAsCompilation']):
        extrasPath = filepath

    if (
            int(track.album['discTotal']) > 1 and (
            (settings['createAlbumFolder'] and settings['createCDFolder']) and
            (not track.singleDownload or (track.singleDownload and settings['createSingleFolder'])) and
            (not track.playlist or
                (track.playlist and settings['tags']['savePlaylistAsCompilation']) or
                (track.playlist and settings['createStructurePlaylist'])
            )
    )):
        filepath = filepath / f'CD{str(track.discNumber)}'

    return (filepath, artistPath, coverPath, extrasPath)


def settingsRegex(filename, track, settings):
    filename = filename.replace("%title%", fixName(track.title, settings['illegalCharacterReplacer']))
    filename = filename.replace("%artist%", fixName(track.mainArtist['name'], settings['illegalCharacterReplacer']))
    filename = filename.replace("%artists%", fixName(", ".join(track.artists), settings['illegalCharacterReplacer']))
    filename = filename.replace("%allartists%", fixName(track.artistsString, settings['illegalCharacterReplacer']))
    filename = filename.replace("%mainartists%", fixName(track.mainArtistsString, settings['illegalCharacterReplacer']))
    if track.featArtistsString:
        filename = filename.replace("%featartists%", fixName('('+track.featArtistsString+')', settings['illegalCharacterReplacer']))
    else:
        filename = filename.replace("%featartists%", '')
    filename = filename.replace("%album%", fixName(track.album['title'], settings['illegalCharacterReplacer']))
    filename = filename.replace("%albumartist%", fixName(track.album['mainArtist']['name'], settings['illegalCharacterReplacer']))
    filename = filename.replace("%tracknumber%", pad(track.trackNumber, track.album['trackTotal'], settings))
    filename = filename.replace("%tracktotal%", str(track.album['trackTotal']))
    filename = filename.replace("%discnumber%", str(track.discNumber))
    filename = filename.replace("%disctotal%", str(track.album['discTotal']))
    if len(track.album['genre']) > 0:
        filename = filename.replace("%genre%",
                                    fixName(track.album['genre'][0], settings['illegalCharacterReplacer']))
    else:
        filename = filename.replace("%genre%", "Unknown")
    filename = filename.replace("%year%", str(track.date['year']))
    filename = filename.replace("%date%", track.dateString)
    filename = filename.replace("%bpm%", str(track.bpm))
    filename = filename.replace("%label%", fixName(track.album['label'], settings['illegalCharacterReplacer']))
    filename = filename.replace("%isrc%", track.ISRC)
    filename = filename.replace("%upc%", track.album['barcode'])
    filename = filename.replace("%explicit%", "(Explicit)" if track.explicit else "")

    filename = filename.replace("%track_id%", str(track.id))
    filename = filename.replace("%album_id%", str(track.album['id']))
    filename = filename.replace("%artist_id%", str(track.mainArtist['id']))
    if track.playlist:
        filename = filename.replace("%playlist_id%", str(track.playlist['playlistId']))
        filename = filename.replace("%position%", pad(track.position, track.playlist['trackTotal'], settings))
    else:
        filename = filename.replace("%playlist_id%", '')
        filename = filename.replace("%position%", pad(track.trackNumber, track.album['trackTotal'], settings))
    filename = filename.replace('\\', pathSep).replace('/', pathSep)
    return antiDot(fixLongName(filename))


def settingsRegexAlbum(foldername, album, settings, playlist=None):
    if playlist and settings['tags']['savePlaylistAsCompilation']:
        foldername = foldername.replace("%album_id%", "pl_" + str(playlist['playlistId']))
        foldername = foldername.replace("%genre%", "Compile")
    else:
        foldername = foldername.replace("%album_id%", str(album['id']))
        if len(album['genre']) > 0:
            foldername = foldername.replace("%genre%", fixName(album['genre'][0], settings['illegalCharacterReplacer']))
        else:
            foldername = foldername.replace("%genre%", "Unknown")
    foldername = foldername.replace("%album%", fixName(album['title'], settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%artist%",
                                    fixName(album['mainArtist']['name'], settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%artist_id%", str(album['mainArtist']['id']))
    foldername = foldername.replace("%tracktotal%", str(album['trackTotal']))
    foldername = foldername.replace("%disctotal%", str(album['discTotal']))
    foldername = foldername.replace("%type%", fixName(album['recordType'].capitalize(), settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%upc%", album['barcode'])
    foldername = foldername.replace("%explicit%", "(Explicit)" if album['explicit'] else "")
    foldername = foldername.replace("%label%", fixName(album['label'], settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%year%", str(album['date']['year']))
    foldername = foldername.replace("%date%", album['dateString'])
    foldername = foldername.replace("%bitrate%", bitrateLabels[int(album['bitrate'])])

    foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
    return antiDot(fixLongName(foldername))


def settingsRegexArtist(foldername, artist, settings):
    foldername = foldername.replace("%artist%", fixName(artist['name'], settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%artist_id%", str(artist['id']))
    foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
    return antiDot(fixLongName(foldername))


def settingsRegexPlaylist(foldername, playlist, settings):
    foldername = foldername.replace("%playlist%", fixName(playlist['title'], settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%playlist_id%", fixName(playlist['playlistId'], settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%owner%", fixName(playlist['owner']['name'], settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%owner_id%", str(playlist['owner']['id']))
    foldername = foldername.replace("%year%", str(playlist['date']['year']))
    foldername = foldername.replace("%date%", str(playlist['dateString']))
    foldername = foldername.replace("%explicit%", "(Explicit)" if playlist['explicit'] else "")
    foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
    return antiDot(fixLongName(foldername))

def settingsRegexPlaylistFile(foldername, queueItem, settings):
    foldername = foldername.replace("%title%", fixName(queueItem.title, settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%artist%", fixName(queueItem.artist, settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%size%", str(queueItem.size))
    foldername = foldername.replace("%type%", fixName(queueItem.type, settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%id%", fixName(queueItem.id, settings['illegalCharacterReplacer']))
    foldername = foldername.replace("%bitrate%", bitrateLabels[int(queueItem.bitrate)])
    foldername = foldername.replace('\\', pathSep).replace('/', pathSep).replace(pathSep, settings['illegalCharacterReplacer'])
    return antiDot(fixLongName(foldername))
