import os

from .notifier import Notifier
from .player_vlc import Player

class SoloTool:
    def __init__(self, player=None):
        self._player = Player() if player is None else player
        self._notifier = Notifier(self._player)
        self._songs = []
        self._song = None
        self._keyPoints = []
        self._keyPoint = None

    def _updateSong(self, index):
        self._song = index
        path = self._songs[index]
        self._player.setCurrentSong(path)
        self._keyPoint = 0.0
        self._notifier.notify(Notifier.CURRENT_SONG_EVENT, index)
        self._notifier.notify(Notifier.CURRENT_KEY_POINT_EVENT, index)

    @staticmethod
    def _keyPointValid(kp: float) -> bool:
        return kp is not None and kp >= 0.0 and kp < 1.0

    @property
    def songs(self) -> list[str]:
        return self._songs.copy()

    def addSong(self, path: str) -> None:
        if not os.path.isfile(path):
            raise FileNotFoundError(path)
        if path in self._songs:
            return
        self._songs.append(path)
        self._keyPoints.append([])
        self._notifier.notify(Notifier.SONG_LIST_EVENT, self.songs)
        if self.song is None:
            self.song = 0

    @property
    def song(self) -> int:
        return self._song

    @song.setter
    def song(self, new: int) -> None:
        if new is not None \
           and new >= 0 \
           and new < len(self._songs) \
           and new != self._song:
            self._updateSong(new)

    @property
    def keyPoints(self) -> list[float]:
        if self._song is None:
            return None
        return self._keyPoints[self._song].copy()

    @keyPoints.setter
    def keyPoints(self, new: list[float]) -> None:
        if new is not None and self._song is not None:
            sanitized = sorted(list(set([p for p in new if SoloTool._keyPointValid(p)])))
            self._keyPoints[self._song] = sanitized
            self._notifier.notify(Notifier.KEY_POINTS_EVENT, sanitized.copy())

    @property
    def keyPoint(self) -> float:
        return self._keyPoint

    @keyPoint.setter
    def keyPoint(self, new: float) -> None:
        if self._song is not None and SoloTool._keyPointValid(new) and new != self._keyPoint:
            self._keyPoint = new
            self._notifier.notify(Notifier.CURRENT_KEY_POINT_EVENT, new)

    def play(self):
        self._player.play()

    def pause(self):
        self._player.pause()

    def stop(self):
        self._player.stop()

    @property
    def playing(self) -> bool:
        return self._player.isPlaying()

    def jump(self):
        self._player.setPlaybackPosition(self._keyPoint)

    @property
    def rate(self) -> float:
        return self._player.getPlaybackRate()

    @rate.setter
    def rate(self, new: float) -> None:
        if new is not None and new >= 0.0 and new != self._player.getPlaybackRate():
            self._player.setPlaybackRate(new)
            self._notifier.notify(Notifier.PLAYBACK_RATE_EVENT, new)

    @property
    def volume(self) -> float:
        return self._player.getPlaybackVolume()

    @volume.setter
    def volume(self, new: float) -> None:
        if new is not None and new >= 0.0 and new != self._player.getPlaybackVolume():
            self._player.setPlaybackVolume(new)
            self._notifier.notify(Notifier.PLAYBACK_VOLUME_EVENT, new)

    @property
    def position(self) -> float:
        return self._player.getPlaybackPosition()

    @position.setter
    def position(self, new: float) -> None:
        if new is not None and new != self._player.getPlaybackPosition():
            self._player.setPlaybackPosition(min(max(0.0, new), 1.0))

    def registerSongSelectionCallback(self, callback):
        self._notifier.registerCallback(Notifier.CURRENT_SONG_EVENT, callback)

    def registerSongListCallback(self, callback):
        self._notifier.registerCallback(Notifier.SONG_LIST_EVENT, callback)

    def registerPlayingStateCallback(self, callback):
        self._notifier.registerCallback(Notifier.PLAYING_STATE_EVENT, callback)

    def registerVolumeCallback(self, callback):
        self._notifier.registerCallback(Notifier.PLAYBACK_VOLUME_EVENT, callback)

    def registerRateCallback(self, callback):
        self._notifier.registerCallback(Notifier.PLAYBACK_RATE_EVENT, callback)

    def registerCurrentKeyPointCallback(self, callback):
        self._notifier.registerCallback(Notifier.CURRENT_KEY_POINT_EVENT, callback)

    def registerKeyPointsCallback(self, callback):
        self._notifier.registerCallback(Notifier.KEY_POINTS_EVENT, callback)