from solo_tool import SoloTool
from player_mock import Player as MockPlayer
import pathlib
import shutil

def test_playerControls():
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)
    
    assert mockPlayer.state == MockPlayer.STOPPED
    assert uut.isPlaying() == False
    uut.play()
    assert mockPlayer.state == MockPlayer.PLAYING
    assert uut.isPlaying() == True
    uut.pause()
    assert mockPlayer.state == MockPlayer.PAUSED
    assert uut.isPlaying() == False
    uut.stop()
    assert mockPlayer.state == MockPlayer.STOPPED
    assert uut.isPlaying() == False

    assert mockPlayer.rate == 1.0
    uut.setPlaybackRate(0.5)
    assert mockPlayer.rate == 0.5

    assert mockPlayer.position == 0.0
    uut.setPlaybackPosition(0.5)
    assert mockPlayer.position == 0.5

    assert mockPlayer.volume == 1.0
    uut.setPlaybackVolume(0.5)
    assert mockPlayer.volume == 0.5

def test_addAndSetSongs():
    songs = [
        "test.flac",
        "test.mp3"
    ]
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)
    
    for s in songs:
        uut.addSong(s)
    assert mockPlayer.currentSong == None
    
    for i, s in enumerate(songs):
        uut.setSong(i)
        assert mockPlayer.currentSong == songs[i]

def test_nextAndPreviousSong():
    songs = [
        "test.flac",
        "test.mp3"
    ]
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)
    
    for s in songs:
        uut.addSong(s)
    assert mockPlayer.currentSong == None
    
    uut.nextSong()
    assert mockPlayer.currentSong == songs[0]
    
    uut.previousSong()
    assert mockPlayer.currentSong == songs[0]

    uut.nextSong()
    assert mockPlayer.currentSong == songs[1]

    uut.nextSong()
    assert mockPlayer.currentSong == songs[1]

def test_addAndSetAbLimits():
    song = "test.flac"
    abLimits = [
        [0.2, 0.4],
        [0.1, 0.3]
    ]
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)

    uut.addSong(song)
    uut.setSong(0)

    uut.storeAbLimits(abLimits[0][0], abLimits[0][1])
    uut.storeAbLimits(abLimits[1][0], abLimits[1][1])

    mockPlayer.position = 0.0
    uut.tick()
    assert mockPlayer.position == 0.0

    mockPlayer.position = 0.5
    uut.tick()
    assert mockPlayer.position == 0.5

    uut.loadAbLimits(0)

    uut.tick()
    assert mockPlayer.position == 0.5

    uut.setAbLimitEnable(True)

    uut.tick()
    assert mockPlayer.position == 0.2

    uut.tick()
    assert mockPlayer.position == 0.2

    uut.loadAbLimits(1)
    uut.tick()
    assert mockPlayer.position == 0.2

    mockPlayer.position = 0.8
    uut.tick()
    assert mockPlayer.position == 0.1

def test_multipleSongsAndAbLimits():
    songs = [
        "test.flac",
        "test.mp3"
    ]
    abLimits = [
        [0.2, 0.4],
        [0.5, 0.7]
    ]
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)
    
    for s in songs:
        uut.addSong(s)

    for i, l in enumerate(abLimits):
        uut.setSong(i)
        uut.storeAbLimits(l[0], l[1])

    uut.setAbLimitEnable(True)
   
    for i, l in enumerate(abLimits):
        uut.setSong(i)
        uut.loadAbLimits(0)

        mockPlayer.position = l[0]
        uut.tick()
        assert mockPlayer.position == l[0]

        mockPlayer.position = l[1] + 0.1
        uut.tick()
        assert mockPlayer.position == l[0]

def test_storeAbLimitsWithoutSong():
    song = "test.flac"
    abLimit = [0.2, 0.4]
    overflow = abLimit[1] + 0.1
    default = 0.0
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)
    mockPlayer.position = overflow
    uut.setAbLimitEnable(True)

    uut.storeAbLimits(abLimit[0], abLimit[1])
    uut.tick()
    assert mockPlayer.position == default
    mockPlayer.position = overflow
    
    uut.loadAbLimits(0)
    uut.tick()
    assert mockPlayer.position == default
    mockPlayer.position = overflow

    uut.addSong(song)
    uut.tick()
    assert mockPlayer.position == default
    mockPlayer.position = overflow

    uut.loadAbLimits(0)
    uut.tick()
    assert mockPlayer.position == default
    mockPlayer.position = overflow

    uut.setSong(0)
    uut.tick()
    assert mockPlayer.position == default
    mockPlayer.position = overflow

    uut.loadAbLimits(0)
    uut.tick()
    assert mockPlayer.position == default
    mockPlayer.position = overflow

    uut.storeAbLimits(abLimit[0], abLimit[1])
    uut.tick()
    assert mockPlayer.position == default
    mockPlayer.position = overflow

    uut.loadAbLimits(0)
    uut.tick()
    assert mockPlayer.position == abLimit[0]

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

def test_loadAndSaveSession(tmp_path):
    copyTestFiles(tmp_path)
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)

    loadedSessionFile = tmp_path / "test_session.json"
    savedSessionFile = tmp_path / "test_session_save.json"

    uut.loadSession(loadedSessionFile)
    uut.saveSession(savedSessionFile)

    import json
    with open(loadedSessionFile, "r") as f:
        loadedSession = json.loads(f.read())
        
    with open(savedSessionFile, "r") as f:
        savedSession = json.loads(f.read())

    assert loadedSession == savedSession

def test_addInexistentFile():
    song = "not/a/real/file"

    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)

    uut.addSong(song)
    uut.setSong(0)

    assert mockPlayer.currentSong == None

def test_getters():
    song = "test.flac"
    abLimit = [0.2, 0.4]
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)

    uut.addSong(song)
    uut.setSong(0)
    uut.storeAbLimits(abLimit[0], abLimit[1])

    assert uut.getSongs() == [song]

    limits = uut.getStoredAbLimits()
    assert len(limits) == 1
    assert limits[0][0] == abLimit[0]
    assert limits[0][1] == abLimit[1]

    mockPlayer.position = 0.8
    assert uut.getPlaybackPosition() == 0.8

def test_setTemporaryLimits():
    song = "test.flac"
    abLimits = [
        [0.2, 0.4],
        [0.1, 0.4]
    ]
    overflow = 0.5
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)

    uut.setAbLimitEnable(True)
    mockPlayer.position = overflow
    uut.addSong(song)
    uut.setSong(0)
    uut.storeAbLimits(abLimits[0][0], abLimits[0][1])
    uut.loadAbLimits(0)

    uut.setAbLimits(abLimits[1][0], abLimits[1][1])
    uut.tick()
    assert mockPlayer.position == abLimits[1][0]

def test_jumpToA():
    song = "test.flac"
    abLimits = (0.2, 0.4)
    initialPosition = 0.8
    mockPlayer = MockPlayer()
    uut = SoloTool(mockPlayer)

    mockPlayer.position = initialPosition
    
    uut.jumpToA()
    assert mockPlayer.position == 0.0 # default AB controller A limit

    uut.setAbLimits(abLimits[0], abLimits[1])
    uut.jumpToA()
    assert mockPlayer.position == abLimits[0]