from librespot.audio.decoders import AudioQuality
from tabulate import tabulate
import os

from .album import download_album, download_artist_albums
from .const import TRACK, NAME, ID, ARTIST, ARTISTS, ITEMS, TRACKS, EXPLICIT, ALBUM, ALBUMS, \
    OWNER, PLAYLIST, PLAYLISTS, DISPLAY_NAME
from .playlist import get_playlist_songs, get_playlist_info, download_from_user_playlist, download_playlist
from .podcast import download_episode, get_show_episodes
from .termoutput import Printer, PrintChannel
from .track import download_track, get_saved_tracks
from .utils import splash, split_input, regex_input_for_urls
from .zspotify import ZSpotify

SEARCH_URL = 'https://api.spotify.com/v1/search'


def client(args) -> None:
    """ Connects to spotify to perform query's and get songs to download """
    ZSpotify(args)

    Printer.print(PrintChannel.SPLASH, splash())

    if ZSpotify.check_premium():
        Printer.print(PrintChannel.SPLASH, '[ DETECTED PREMIUM ACCOUNT - USING VERY_HIGH QUALITY ]\n\n')
        ZSpotify.DOWNLOAD_QUALITY = AudioQuality.VERY_HIGH
    else:
        Printer.print(PrintChannel.SPLASH, '[ DETECTED FREE ACCOUNT - USING HIGH QUALITY ]\n\n')
        ZSpotify.DOWNLOAD_QUALITY = AudioQuality.HIGH

    if args.download:
        urls = []
        filename = args.download
        if os.path.exists(filename):
            with open(filename, 'r', encoding='utf-8') as file:
                urls.extend([line.strip() for line in file.readlines()])

            download_from_urls(urls)

        else:
            Printer.print(PrintChannel.ERRORS, f'File {filename} not found.\n')

    if args.urls:
        download_from_urls(args.urls)

    if args.playlist:
        download_from_user_playlist()

    if args.liked_songs:
        for song in get_saved_tracks():
            if not song[TRACK][NAME] or not song[TRACK][ID]:
                Printer.print(PrintChannel.SKIPS, '###   SKIPPING:  SONG DOES NOT EXIST ON SPOTIFY ANYMORE   ###' + "\n")
            else:
                download_track('liked', song[TRACK][ID])

    if args.search_spotify:
        search_text = ''
        while len(search_text) == 0:
            search_text = input('Enter search or URL: ')

        if not download_from_urls([search_text]):
            search(search_text)

def download_from_urls(urls: list[str]) -> bool:
    """ Downloads from a list of spotify urls """
    download = False

    for spotify_url in urls:
        track_id, album_id, playlist_id, episode_id, show_id, artist_id = regex_input_for_urls(
            spotify_url)

        if track_id is not None:
            download = True
            download_track('single', track_id)
        elif artist_id is not None:
            download = True
            download_artist_albums(artist_id)
        elif album_id is not None:
            download = True
            download_album(album_id)
        elif playlist_id is not None:
            download = True
            playlist_songs = get_playlist_songs(playlist_id)
            name, _ = get_playlist_info(playlist_id)
            enum = 1
            char_num = len(str(len(playlist_songs)))
            for song in playlist_songs:
                if not song[TRACK][NAME] or not song[TRACK][ID]:
                    Printer.print(PrintChannel.SKIPS, '###   SKIPPING:  SONG DOES NOT EXIST ON SPOTIFY ANYMORE   ###' + "\n")
                else:
                    download_track('playlist', song[TRACK][ID], extra_keys=
                    {
                        'playlist_song_name': song[TRACK][NAME],
                        'playlist': name,
                        'playlist_num': str(enum).zfill(char_num),
                        'playlist_id': playlist_id,
                        'playlist_track_id': song[TRACK][ID]
                    })
                    enum += 1
        elif episode_id is not None:
            download = True
            download_episode(episode_id)
        elif show_id is not None:
            download = True
            for episode in get_show_episodes(show_id):
                download_episode(episode)

    return download


def search(search_term):
    """ Searches Spotify's API for relevant data """
    params = {'limit': '10',
              'offset': '0',
              'q': search_term,
              'type': 'track,album,artist,playlist'}

    # Parse args
    splits = search_term.split()
    for split in splits:
        index = splits.index(split)

        if split[0] == '-' and len(split) > 1:
            if len(splits)-1 == index:
                raise IndexError('No parameters passed after option: {}\n'.
                                 format(split))

        if split == '-l' or split == '-limit':
            try:
                int(splits[index+1])
            except ValueError:
                raise ValueError('Paramater passed after {} option must be an integer.\n'.
                                 format(split))
            if int(splits[index+1]) > 50:
                raise ValueError('Invalid limit passed. Max is 50.\n')
            params['limit'] = splits[index+1]

        if split == '-t' or split == '-type':

            allowed_types = ['track', 'playlist', 'album', 'artist']
            passed_types = []
            for i in range(index+1, len(splits)):
                if splits[i][0] == '-':
                    break

                if splits[i] not in allowed_types:
                    raise ValueError('Parameters passed after {} option must be from this list:\n{}'.
                                     format(split, '\n'.join(allowed_types)))

                passed_types.append(splits[i])
            params['type'] = ','.join(passed_types)

    if len(params['type']) == 0:
        params['type'] = 'track,album,artist,playlist'

    # Clean search term
    search_term_list = []
    for split in splits:
        if split[0] == "-":
            break
        search_term_list.append(split)
    if not search_term_list:
        raise ValueError("Invalid query.")
    params["q"] = ' '.join(search_term_list)

    resp = ZSpotify.invoke_url_with_params(SEARCH_URL, **params)

    counter = 1
    dics = []

    total_tracks = 0
    if TRACK in params['type'].split(','):
        tracks = resp[TRACKS][ITEMS]
        if len(tracks) > 0:
            print('###  TRACKS  ###')
            track_data = []
            for track in tracks:
                if track[EXPLICIT]:
                    explicit = '[E]'
                else:
                    explicit = ''

                track_data.append([counter, f'{track[NAME]} {explicit}',
                                  ','.join([artist[NAME] for artist in track[ARTISTS]])])
                dics.append({
                    ID: track[ID],
                    NAME: track[NAME],
                    'type': TRACK,
                })

                counter += 1
            total_tracks = counter - 1
            print(tabulate(track_data, headers=[
                  'S.NO', 'Name', 'Artists'], tablefmt='pretty'))
            print('\n')
            del tracks
            del track_data

    total_albums = 0
    if ALBUM in params['type'].split(','):
        albums = resp[ALBUMS][ITEMS]
        if len(albums) > 0:
            print('###  ALBUMS  ###')
            album_data = []
            for album in albums:
                album_data.append([counter, album[NAME],
                                  ','.join([artist[NAME] for artist in album[ARTISTS]])])
                dics.append({
                    ID: album[ID],
                    NAME: album[NAME],
                    'type': ALBUM,
                })

                counter += 1
            total_albums = counter - total_tracks - 1
            print(tabulate(album_data, headers=[
                  'S.NO', 'Album', 'Artists'], tablefmt='pretty'))
            print('\n')
            del albums
            del album_data

    total_artists = 0
    if ARTIST in params['type'].split(','):
        artists = resp[ARTISTS][ITEMS]
        if len(artists) > 0:
            print('###  ARTISTS  ###')
            artist_data = []
            for artist in artists:
                artist_data.append([counter, artist[NAME]])
                dics.append({
                    ID: artist[ID],
                    NAME: artist[NAME],
                    'type': ARTIST,
                })
                counter += 1
            total_artists = counter - total_tracks - total_albums - 1
            print(tabulate(artist_data, headers=[
                  'S.NO', 'Name'], tablefmt='pretty'))
            print('\n')
            del artists
            del artist_data

    total_playlists = 0
    if PLAYLIST in params['type'].split(','):
        playlists = resp[PLAYLISTS][ITEMS]
        if len(playlists) > 0:
            print('###  PLAYLISTS  ###')
            playlist_data = []
            for playlist in playlists:
                playlist_data.append(
                    [counter, playlist[NAME], playlist[OWNER][DISPLAY_NAME]])
                dics.append({
                    ID: playlist[ID],
                    NAME: playlist[NAME],
                    'type': PLAYLIST,
                })
                counter += 1
            total_playlists = counter - total_artists - total_tracks - total_albums - 1
            print(tabulate(playlist_data, headers=[
                  'S.NO', 'Name', 'Owner'], tablefmt='pretty'))
            print('\n')
            del playlists
            del playlist_data

    if total_tracks + total_albums + total_artists + total_playlists == 0:
        print('NO RESULTS FOUND - EXITING...')
    else:
        selection = ''
        print('> SELECT A DOWNLOAD OPTION BY ID')
        print('> SELECT A RANGE BY ADDING A DASH BETWEEN BOTH ID\'s')
        print('> OR PARTICULAR OPTIONS BY ADDING A COMMA BETWEEN ID\'s\n')
        while len(selection) == 0:
            selection = str(input('ID(s): '))
        inputs = split_input(selection)
        for pos in inputs:
            position = int(pos)
            for dic in dics:
                print_pos = dics.index(dic) + 1
                if print_pos == position:
                    if dic['type'] == TRACK:
                        download_track('single', dic[ID])
                    elif dic['type'] == ALBUM:
                        download_album(dic[ID])
                    elif dic['type'] == ARTIST:
                        download_artist_albums(dic[ID])
                    else:
                        download_playlist(dic)
