# import os
import threading
import vlc  # type: ignore

#
from config import Config
from helpers import file_is_unreadable
from typing import Optional
from time import sleep

from log import log

from PyQt6.QtCore import (  # type: ignore
    QRunnable,
    QThreadPool,
)

lock = threading.Lock()


class FadeTrack(QRunnable):
    def __init__(self, player: vlc.MediaPlayer, fade_seconds) -> None:
        super().__init__()
        self.player = player
        self.fade_seconds = fade_seconds

    def run(self) -> None:
        """
        Implementation of fading the player
        """

        if not self.player:
            return

        # Reduce volume logarithmically
        total_steps = self.fade_seconds * Config.FADEOUT_STEPS_PER_SECOND
        db_reduction_per_step = Config.FADEOUT_DB / total_steps
        reduction_factor_per_step = pow(10, (db_reduction_per_step / 20))

        volume = self.player.audio_get_volume()

        for i in range(1, total_steps + 1):
            self.player.audio_set_volume(
                int(volume * pow(reduction_factor_per_step, i))
            )
            sleep(1 / Config.FADEOUT_STEPS_PER_SECOND)

        self.player.stop()
        log.debug(f"Releasing player {self.player=}")
        self.player.release()


class Music:
    """
    Manage the playing of music tracks
    """

    def __init__(self) -> None:
        self.VLC = vlc.Instance()
        self.player = None
        self.max_volume = Config.VOLUME_VLC_DEFAULT

    def fade(self, fade_seconds: int = Config.FADEOUT_SECONDS) -> None:
        """
        Fade the currently playing track.

        The actual management of fading runs in its own thread so as not
        to hold up the UI during the fade.
        """

        if not self.player:
            return

        if not self.player.get_position() > 0 and self.player.is_playing():
            return

        # Take a copy of current player to allow another track to be
        # started without interfering here
        with lock:
            p = self.player
            self.player = None

        pool = QThreadPool.globalInstance()
        fader = FadeTrack(p, fade_seconds=fade_seconds)
        pool.start(fader)

    def get_position(self) -> Optional[float]:
        """Return current position"""

        if not self.player:
            return None
        return self.player.get_position()

    def play(self, path: str, position: Optional[float] = None) -> None:
        """
        Start playing the track at path.

        Log and return if path not found.
        """

        if file_is_unreadable(path):
            log.error(f"play({path}): path not readable")
            return None

        media = self.VLC.media_new_path(path)
        self.player = media.player_new_from_media()
        if self.player:
            _ = self.player.play()
            self.set_volume(self.max_volume)
            if position:
                self.player.set_position(position)

    def set_volume(self, volume=None, set_default=True) -> None:
        """Set maximum volume used for player"""

        if not self.player:
            return

        if set_default:
            self.max_volume = volume

        if volume is None:
            volume = Config.VOLUME_VLC_DEFAULT

        self.player.audio_set_volume(volume)

    def stop(self) -> float:
        """Immediately stop playing"""

        if not self.player:
            return 0.0

        p = self.player
        self.player = None

        with lock:
            position = p.get_position()
            p.stop()
            p.release()
            p = None
            return position
