import pathlib
import shutil
import pytest

from solo_tool.solo_tool import SoloTool
from player_mock import Player as MockPlayer

@pytest.fixture
def mockPlayer():
    return MockPlayer()

@pytest.fixture
def uut(mockPlayer):
    return SoloTool(mockPlayer)

@pytest.fixture
def prepared_tmp_path(tmp_path):
    testFiles = [
        "test.flac",
        "test.mp3",
        "test_session.json"
    ]
    for f in testFiles:
        shutil.copy(pathlib.Path(f), tmp_path)

    return tmp_path

def test_playerControls(uut, mockPlayer):
    assert not mockPlayer.playing
    assert not uut.playing
    uut.play()
    assert mockPlayer.playing
    assert uut.playing
    uut.pause()
    assert not mockPlayer.playing
    assert not uut.playing

    assert mockPlayer.rate == 1.0
    uut.rate = 0.5
    assert mockPlayer.rate == 0.5
    assert uut.rate == 0.5

    assert mockPlayer.position == 0.0
    uut.position = 0.5
    assert mockPlayer.position == 0.5
    assert uut.position == 0.5

    assert mockPlayer.volume == 1.0
    uut.volume = 0.5
    assert mockPlayer.volume == 0.5
    assert uut.volume == 0.5

def test_sanitizePlaybackRate(uut):
    # Initial value
    assert uut.rate == 1.0

    # Valid rates are >= 0.0, invalid is ignored
    uut.rate = -0.1
    assert uut.rate == 1.0

    uut.rate = 0.0
    assert uut.rate == 0.0
    
    uut.rate = 0.0001
    assert uut.rate == 0.0001

    uut.rate = 150.0
    assert uut.rate == 150.0

def test_sanitizePlaybackPosition(uut):
    # Initial value
    assert uut.position == 0.0

    # Valid positions are in [0, 1], invalid is limited
    uut.position = 0.2
    assert uut.position == 0.2

    uut.position = -0.1
    assert uut.position == 0.0

    uut.position = 1.0
    assert uut.position == 1.0

    uut.position = 0.4
    assert uut.position == 0.4

    uut.position = 1.5
    assert uut.position == 1.0

def test_sanitizePlaybackVolume(uut):
    # Initial value
    assert uut.volume == 1.0

    # Valid volumes are >= 0.0, invalid is ignored
    uut.volume = -0.1
    assert uut.volume == 1.0

    uut.volume = 0.0
    assert uut.volume == 0.0

    uut.volume = 1.0
    assert uut.volume == 1.0

    uut.volume = 150.0
    assert uut.volume == 150.0

def test_playingStateNotification(uut, mockPlayer):
    song = "test.flac"
    uut.addSong(song)

    called = False
    receivedValue = None
    def callback(value):
        nonlocal called, receivedValue
        called = True
        receivedValue = value

    uut.registerPlayingStateCallback(callback)

    assert not mockPlayer.playing
    assert not called

    uut.play()
    assert called
    assert receivedValue == True
    called = False
    uut.play()
    assert not called

    uut.pause()
    assert called
    assert receivedValue == False
    called = False
    uut.pause()
    assert not called

def test_playbackVolumeNotification(uut, mockPlayer):
    song = "test.flac"
    uut.addSong(song)
    uut.song = 0

    called = False
    receivedValue = None
    def callback(value):
        nonlocal called, receivedValue
        called = True
        receivedValue = value

    uut.registerVolumeCallback(callback)

    assert not called

    uut.volume = 0.3
    assert called
    assert receivedValue == 0.3
    called = False

    uut.volume = 0.3
    assert not called

def test_playbackRateNotification(uut, mockPlayer):
    song = "test.flac"
    uut.addSong(song)
    uut.song = 0

    called = False
    receivedValue = None
    def callback(value):
        nonlocal called, receivedValue
        called = True
        receivedValue = value

    uut.registerRateCallback(callback)

    assert not called

    uut.rate = 0.5
    assert called
    assert receivedValue == 0.5
    called = False

    uut.rate = 0.5
    assert not called