"""song.py - Used for song related functions.

All the functions used to interact with the downloaded song are defined here.
"""

from colorama import Fore, Style
from mutagen.id3 import ID3, APIC, TIT2, TPE1, TALB, TCON, TRCK, TYER
from mutagen.mp3 import MP3
from mutagen.mp4 import MP4, MP4Cover
import requests
from ytmdl import prepend, defaults, logger
import os
# import traceback

logger = logger.Logger("song")

# ----------------------cover--------------------


def dwCover(SONG_INFO, index):
    """Download the song cover img from itunes."""
    # Try to download the cover art as cover.jpg in temp
    logger.info("Preparing the album cover")
    try:
        imgURL = SONG_INFO[index].artwork_url_100

        # Check if the passed imgURL is a local file
        # this is possible if the metadata was entered manually.
        imgURL = os.path.expanduser(imgURL)
        if os.path.exists(imgURL):
            # Probably a file, read it in binary and extract the data
            # then return.
            content = open(imgURL, "rb").read()
            with open(defaults.DEFAULT.COVER_IMG, 'wb') as f:
                f.write(content)
            return True

        # Else might be an URL
        try:
            # Try to get 512 cover art
            imgURL = imgURL.replace('100x100', '2048x2048')
        except Exception:
            pass

        r = requests.get(imgURL)

        with open(defaults.DEFAULT.COVER_IMG, 'wb') as f:
            f.write(r.content)

        return True
    except TimeoutError:
        prepend.PREPEND(2)
        print('Could not get album cover. Are you connected to internet?\a')
        return False
    except Exception as e:
        logger.warning("Error while trying to download image, skipping!: {}".format(e))
        return False
    else:
        return False

# -----------------------tag----------------------


def print_choice(beg, end, SONG_INFO, type):
    """Print the available choices."""
    # Check if end is more than length of SONG_INFO
    if end > len(SONG_INFO):
        end = len(SONG_INFO)

    while beg != end:
        print(Fore.LIGHTMAGENTA_EX, end='')
        print(' [' + str(beg+1) + '] ', end='')
        print(Style.RESET_ALL, end='')
        print(Fore.LIGHTCYAN_EX, end='')
        if type == 'metadata':
            print(SONG_INFO[beg].track_name, end='')
        if type == 'mp3':
            print(SONG_INFO[beg]['title'], end='')
        print(Style.RESET_ALL, end='')
        print(' by ', end='')
        print(Fore.YELLOW, end='')
        if type == 'metadata':
            print(SONG_INFO[beg].artist_name, end='')
        if type == 'mp3':
            print(SONG_INFO[beg]['author_name'], end='')
            print(Style.RESET_ALL, end='')
            print(' with dur ', end='')
            print(Fore.GREEN, end='')
            print("{}".format(SONG_INFO[beg]['duration']), end='')
        print(Style.RESET_ALL)

        beg += 1

    # Before exiting print another choice to show more
    if end < len(SONG_INFO):
        print(Fore.LIGHTMAGENTA_EX, end='')
        print(' [0]', end='')
        print(Style.RESET_ALL, end='')
        print(Fore.YELLOW, end='')
        print(' More results')
        print(Style.RESET_ALL, end='')


def getChoice(SONG_INFO, type):
    """If more than 1 result from getData then ask for a choice."""
    # Print 5 of the search results
    # In case less, print all

    prepend.PREPEND(1)
    print('Choose One')

    results = len(SONG_INFO)

    if results > 5:
        results = 5

    PRINT_WHOLE = True

    beg = 0
    while True:
        # Print the results first
        if PRINT_WHOLE:
            print_choice(beg, results, SONG_INFO, type)
        prepend.PREPEND(1)
        choice = input('Enter Choice [a valid choice] ')
        choice = int(choice)
        # If the choice is 6 then try to print more results
        if choice <= results and choice > 0:
            break
        elif choice == 0 and results < len(SONG_INFO):
            PRINT_WHOLE = True
            beg = results
            results = beg + 5
        else:
            PRINT_WHOLE = False

    choice = int(choice)
    choice -= 1
    return choice


def set_MP3_data(SONG_INFO, is_quiet, song_path, choice):
    """
    Set the meta data if the passed data is mp3.
    """
    # A variable to see if cover image was added.
    IS_IMG_ADDED = False

    try:
        # If more than one choice then call getChoice
        option = 0
        if len(SONG_INFO) > 1:
            if not is_quiet:
                option = getChoice(SONG_INFO, 'metadata')
            elif choice is not None and choice in range(1, len(SONG_INFO)):
                option = choice

        SONG_PATH = os.path.join(defaults.DEFAULT.SONG_TEMP_DIR,
                                 song_path)

        audio = MP3(SONG_PATH, ID3=ID3)
        data = ID3(SONG_PATH)

        # Download the cover image, if failed, pass
        if dwCover(SONG_INFO, option):
            imagedata = open(defaults.DEFAULT.COVER_IMG, 'rb').read()
            data.add(APIC(3, 'image/jpeg', 3, 'Front cover', imagedata))
            # REmove the image
            os.remove(defaults.DEFAULT.COVER_IMG)
            IS_IMG_ADDED = True

        # If tags are not present then add them
        try:
            audio.add_tags()
        except Exception:
            pass

        audio.save()

        option = int(option)

        data.add(TYER(encoding=3, text=SONG_INFO[option].release_date))
        data.add(TIT2(encoding=3, text=SONG_INFO[option].track_name))
        data.add(TPE1(encoding=3, text=SONG_INFO[option].artist_name))
        data.add(TALB(encoding=3, text=SONG_INFO[option].collection_name))
        data.add(TCON(encoding=3, text=SONG_INFO[option].primary_genre_name))
        data.add(TRCK(encoding=3, text=str(SONG_INFO[option].track_number)))

        data.save()

        defaults.DEFAULT.SONG_NAME_TO_SAVE = SONG_INFO[option].track_name + '.mp3'

        # Rename the downloaded file
        os.rename(SONG_PATH, os.path.join(
                                    defaults.DEFAULT.SONG_TEMP_DIR,
                                    defaults.DEFAULT.SONG_NAME_TO_SAVE
                                ))

        return option, IS_IMG_ADDED

    except Exception as e:
        logger.debug("{}".format(e))
        return e, False


def set_M4A_data(SONG_INFO, is_quiet, song_path, choice):
    """
    Set the tags in the m4a file passed.
    """
    cover_added = False

    try:
        # If more than one choice then call getChoice
        option = 0
        if len(SONG_INFO) > 1:
            if not is_quiet:
                option = getChoice(SONG_INFO, 'metadata')
            elif choice is not None and choice in range(1, len(SONG_INFO)):
                option = choice

        SONG_PATH = os.path.join(defaults.DEFAULT.SONG_TEMP_DIR,
                                 song_path)

        audio = MP4(SONG_PATH)

        # Download the cover image, if failed, pass
        if dwCover(SONG_INFO, option):
            imagedata = open(defaults.DEFAULT.COVER_IMG, 'rb').read()
            audio["covr"] = [MP4Cover(
                                imagedata,
                                imageformat=MP4Cover.FORMAT_JPEG
                            )]
            # REmove the image
            os.remove(defaults.DEFAULT.COVER_IMG)
            cover_added = True

        # If tags are not present then add them
        try:
            audio.add_tags()
        except Exception:
            pass

        audio.save()

        option = int(option)

        # Add the meta data, the key's can be found at
        # https://mutagen.readthedocs.io/en/latest/api/mp4.html#mutagen.mp4.MP4Tags
        audio["\xa9nam"] = SONG_INFO[option].track_name
        audio["\xa9alb"] = SONG_INFO[option].collection_name
        audio["\xa9ART"] = SONG_INFO[option].artist_name
        audio["\xa9day"] = SONG_INFO[option].release_date
        audio["\xa9gen"] = SONG_INFO[option].primary_genre_name

        # Adding track number would probably thwor some kind
        # of render error, will leave for later

        audio.save()

        defaults.DEFAULT.SONG_NAME_TO_SAVE = SONG_INFO[option].track_name + '.m4a'

        # Rename the downloaded file
        os.rename(SONG_PATH, os.path.join(
                                    defaults.DEFAULT.SONG_TEMP_DIR,
                                    defaults.DEFAULT.SONG_NAME_TO_SAVE
                                ))

        return option, cover_added

    except Exception as e:
        return e


def setData(SONG_INFO, is_quiet, song_path, datatype='mp3', choice=None):
    """Add the metadata to the song."""
    if datatype == 'mp3':
        option, img_added = set_MP3_data(
                                SONG_INFO,
                                is_quiet,
                                song_path,
                                choice
                            )
    elif datatype == 'm4a':
        option, img_added = set_M4A_data(
                                SONG_INFO,
                                is_quiet,
                                song_path,
                                choice
                            )

    # Show the written stuff in a better format
    prepend.PREPEND(1)
    print('================================')
    print('  || YEAR: ' + SONG_INFO[option].release_date)
    print('  || TITLE: ' + SONG_INFO[option].track_name)
    print('  || ARTIST: ' + SONG_INFO[option].artist_name)
    print('  || ALBUM: ' + SONG_INFO[option].collection_name)
    print('  || GENRE: ' + SONG_INFO[option].primary_genre_name)
    print('  || TRACK NO: ' + str(SONG_INFO[option].track_number))

    if img_added:
        print('  || ALBUM COVER ADDED')

    prepend.PREPEND(1)
    print('================================')

    return option
