from session_manager import SessionManager
from json import loads, dumps

testSession = [
    {
        "path" : "/path/to/another/song",
        "ab_limits" : None
    },
    {
        "path" : "/path/to/song",
        "ab_limits" : [
            [0.1, 0.2],
            [0.3, 0.4]
        ]
    },
    {
        "path" : "/path/to/something",
        "ab_limits" : [
            [0.1, 0.2]
        ]
    }
]

class PlaylistMock:
    def __init__(self):
        self.lastAddedSong = None
        self.songs = list()

    def addSong(self, s):
        self.songs.append(s)
        self.lastAddedSong = s

    def getSongs(self):
        return self.songs

    def clear(self):
        self.__init__()

class ABControllerMock:
    def __init__(self):
        self.limits = dict()

    def storeLimits(self, aLimit, bLimit, song="current"):
        if song not in self.limits: 
            self.limits[song] = list()
        self.limits[song].append([aLimit, bLimit])
    
    def getStoredLimits(self, song):
        return self.limits.get(song)

    def clear(self):
        self.__init__()

class MockFile:
    def __init__(self, init=""):
        self.contents = init

    def open(self, *args):
        pass

    def write(self, s):
        self.contents += s

    def read(self):
        return self.contents


def test_addSongs():
    songs = [
        "/path/to/song",
        "/path/to/another/song"
    ]

    playlistMock = PlaylistMock()
    uut = SessionManager(playlistMock, None)

    for s in songs:
        uut.addSong(s)
        assert playlistMock.lastAddedSong == s

def test_addAbLimits():
    abLimits = [
        [0.1, 0.2],
        [0.3, 0.4]
    ]

    abControllerMock = ABControllerMock()
    uut = SessionManager(None, abControllerMock)

    for i, ab in enumerate(abLimits):
        uut.storeLimits(ab[0], ab[1])
        assert abControllerMock.limits["current"][i] == ab
 
def test_loadSession():
    playlistMock = PlaylistMock()
    abControllerMock = ABControllerMock()
    uut = SessionManager(playlistMock, abControllerMock)

    sessionFile = MockFile(dumps(testSession))
    uut.loadSession(sessionFile)

    for i, entry in enumerate(testSession):
        expectedSong = entry["path"]
        expectedLimits = entry["ab_limits"]
        loadedSong = playlistMock.songs[i]
        loadedLimits = abControllerMock.limits.get(expectedSong)

        assert loadedSong == expectedSong
        assert loadedLimits == expectedLimits

def test_saveSession():
    playlistMock = PlaylistMock()
    abControllerMock = ABControllerMock()
    uut = SessionManager(playlistMock, abControllerMock)

    for i, entry in enumerate(testSession):
        song = entry["path"]
        playlistMock.addSong(song)

        abLimits = entry["ab_limits"]
        if abLimits is not None:
            for l in abLimits:
                abControllerMock.storeLimits(l[0], l[1], song)

    sessionFile = MockFile()
    uut.saveSession(sessionFile)

    savedSession = loads(sessionFile.read())
    assert savedSession == testSession

def test_loadAndSaveEmptySession():
    playlistMock = PlaylistMock()
    abControllerMock = ABControllerMock()
    uut = SessionManager(playlistMock, abControllerMock)

    sessionFile = MockFile()

    uut.saveSession(sessionFile)
    assert loads(sessionFile.read()) == list()

    uut.loadSession(sessionFile)

    songs = playlistMock.getSongs()
    assert songs == list()
    for s in songs:
        assert abControllerMock.getStoredLimits(s) == None

def test_loadSessionNotAdditive():
    playlistMock = PlaylistMock()
    abControllerMock = ABControllerMock()
    uut = SessionManager(playlistMock, abControllerMock)

    sessionFile = MockFile(dumps(testSession))
    uut.loadSession(sessionFile)
    uut.loadSession(sessionFile)

    songs = playlistMock.getSongs()
    assert len(songs) == len(set(songs))
    for s in songs:
        abLimits = abControllerMock.getStoredLimits(s)
        if abLimits is not None:
            abLimitStr = [f"[{l[0]}, {l[1]}] " for l in abLimits]
            assert len(abLimitStr) == len(set(abLimitStr))