import sys

print("Importing internal dependencies...")

# The badge does support relative imports without a known parent package, but normal python doesn't (it probably does
# but the context is not known to me, and therefore this dirty hack :)
if hasattr(sys, "_called_from_test"):
    from player import (
        next_track,
        get_random_track,
        previous_track,
        volume_raise,
        volume_lower,
        set_playing_track,
        set_current_volume,
        set_playlist,
        next_playlist,
        previous_playlist,
        get_current_volume, current_playlist_directory,
)
    from graphics import (
        set_animation,
        animation_wifi_searching_progress,
        full_sceen_feedback,
        animation_wifi_searching,
        progress_animation,
        default_animation,
        get_previous_animation,
        get_next_animation,
    )
    from settings import (
        KEYS, TRACK_SERVER
    )
else:
    from .player import (
        next_track,
        get_random_track,
        previous_track,
        volume_raise,
        volume_lower,
        set_playing_track,
        set_current_volume,
        set_playlist,
        next_playlist,
        previous_playlist,
        get_current_volume, current_playlist_directory
    )
    from .graphics import (
        set_animation,
        animation_wifi_searching_progress,
        full_sceen_feedback,
        animation_wifi_searching,
        progress_animation,
        default_animation,
        get_previous_animation,
        get_next_animation,
    )
    from .settings import (
        KEYS, TRACK_SERVER
    )

    print("Importing external dependencies...")
    import wifi, audio, keypad, sndmixer, machine, touchpads  # noqa (missing libs while developing)

    print("Imported internal dependencies.")

MUSIC = True
INTERACTION = True
ANIMATIONS = True

# Every time an audio channel is made, it's added to this list. Audio channels can't be just a single variable because
# multiple audio channels might be claimed (and will be) for reasons. So using this trick, we're sure that hitting
# the "next" button actually stops playing everything and moves to the next track.
audio_channels = []


# thnx better radio app :) this is so friendly, would be a shame if something happened to it.
def setvolume(volume):
    set_current_volume(volume)
    for index in audio.handles.keys():
        sndmixer.volume(index, volume)


def stop_all_audio():
    global audio_channels

    # can be multiple channels, and a random new channel is created each time
    # you press next. This might cause two or more songs are playing at the same time.
    # because it's not smart to alter an array while iterating, a "remove list" is created
    # and then the audio channels are removed one by one.
    remove = []
    for audio_channel in audio_channels:
        audio.stop_channel(audio_channel)
        remove.append(audio_channel)
    for item in remove:
        audio_channels.remove(item)


def play_track(track_name):
    global audio_channels

    set_playing_track(track_name)
    stop_all_audio()

    # switching to an animating loading animation is impossible: the display locks while downloading a file.
    if not wifi.status():
        connect_wifi()

    try:
        track_url = "" + TRACK_SERVER + current_playlist_directory() + "/" + track_name
        print("Attempting to retrieve track from: " + track_url)
        audio_channels.append(
            audio.play(
                track_url,
                volume=get_current_volume(),
                loop=False,
                on_finished=play_next,
            ),
        )
    except ValueError as e:
        """
        Exception in keypad event handler
        Traceback (most recent call last):
          File "keypad.py", line 41, in _keypad_interrupt_handler
          File "apps/mod_music_player/__init__.py", line 116, in on_key
          File "apps/mod_music_player/__init__.py", line 64, in play_next
          File "apps/mod_music_player/__init__.py", line 61, in play_track
          File "audio.py", line 73, in play
          File "audio.py", line 26, in _add_channel
            ...
          File "urequests.py", line 111, in get
          File "urequests.py", line 35, in request
        ValueError: WiFi not connected
        :return:
        """
        if "WiFi not connected" in str(e):
            print("Wifi connection issues...")
            connect_wifi()
            play_track(track_name)
    except MemoryError:
        """
        It looks like in some cases files are damaged or unreadable. In such cases try the next song.
        Shame though. :)
        
        Now playing: an-path.xm
        Exception in keypad event handler
        Traceback (most recent call last):
          File "keypad.py", line 41, in _keypad_interrupt_handler
          File "apps/mod_music_player/__init__.py", line 142, in on_key
          File "apps/mod_music_player/__init__.py", line 90, in play_next
          File "apps/mod_music_player/__init__.py", line 87, in play_track
          File "apps/mod_music_player/__init__.py", line 68, in play_track
          File "audio.py", line 73, in play
          File "audio.py", line 43, in _add_channel
        MemoryError: memory allocation failed,
        """
        print("Probably a corrupt or unsupported song is being played.")
        play_next()
    except OSError:
        """
        Traceback (most recent call last):
          File "boot.py", line 62, in <module>
          File "apps/mod_music_player/__init__.py", line 268, in <module>
          File "apps/mod_music_player/__init__.py", line 244, in initialize
          File "apps/mod_music_player/__init__.py", line 159, in play_track
          File "apps/mod_music_player/__init__.py", line 116, in play_track
          File "audio.py", line 73, in play
          File "audio.py", line 43, in _add_channel
        OSError: [Errno 110] ETIMEDOUT
        """
        print("Could not register channels, trying next track...")
        play_next()


def play_next():
    play_track(next_track())


def play_previous():
    play_track(previous_track())


def on_key(key_index, pressed):

    if pressed:
        print("Pressed key: " + str(key_index))

        if key_index == KEYS["previous_track"]:
            full_sceen_feedback()
            play_previous()
            full_sceen_feedback()
        if key_index == KEYS["next_track"]:
            full_sceen_feedback()
            play_next()
            full_sceen_feedback()
        if key_index == KEYS["previous_animation"]:
            set_animation(get_previous_animation())
        if key_index == KEYS["next_animation"]:
            set_animation(get_next_animation())

        full_sceen_feedback()


def vol_up(is_pressed):
    if is_pressed:
        full_sceen_feedback()
        setvolume(volume_raise())


def vol_down(is_pressed):
    if is_pressed:
        full_sceen_feedback()
        setvolume(volume_lower())


def switch_to_next_playlist(is_pressed):
    if is_pressed:
        full_sceen_feedback()
        set_playlist(next_playlist())
        play_next()
        full_sceen_feedback()


def switch_to_previous_playlist(is_pressed):
    if is_pressed:
        full_sceen_feedback()
        set_playlist(previous_playlist())
        play_next()
        full_sceen_feedback()


def connect_wifi():
    print("Creating wifi connection")
    animation_wifi_searching()
    while not wifi.status():
        # show that wifi is expected. The home button still works to exit.
        print("- Attempting to connect to wifi...")
        animation_wifi_searching_progress()
        wifi.connect()
        wifi.wait()
    print("Connected to wifi")


def initialize():
    print("Initializing app.")

    if MUSIC:
        print("Setting up audio.")
        retrieved_volume = machine.nvs_getint("system", "volume")
        if retrieved_volume:
            setvolume(retrieved_volume)

        # setting up a wifi connection is slow, which will be animated.
        connect_wifi()

        print("Playing the first track")
        play_track(get_random_track())

    if ANIMATIONS:
        print("Setting up display effects")
        # Only base timers 0~3 and extended timers 4~11 can be used.
        timer = machine.Timer(3)
        # pretty smooth, 20 fps
        # # mytimer: Period: 100 ms; Repeat: True; Type: Periodic; Running: yes Events: 70; Callbacks: 13; Missed: 57
        # https://techtutorialsx.com/2017/10/07/esp32-micropython-timer-interrupts/
        timer.init(period=100, mode=machine.Timer.PERIODIC, callback=progress_animation)
        print("Showing the first visual")
        set_animation(default_animation)

    if INTERACTION:
        print("Setting up keypad")
        keypad.add_handler(on_key)

        print("Setting up touchpads")
        touchpads.on(touchpads.RIGHT, vol_up)
        touchpads.on(touchpads.LEFT, vol_down)
        touchpads.on(touchpads.CANCEL, switch_to_previous_playlist)
        touchpads.on(touchpads.OK, switch_to_next_playlist)


if not hasattr(sys, "_called_from_test"):
    initialize()