# Standard library imports
import datetime as dt
import unittest

# PyQt imports

# Third party imports

# App imports
from app import helpers

from app.models import (
    db,
    NoteColours,
    Playdates,
    Playlists,
    PlaylistRows,
    Tracks,
)


class TestMMModels(unittest.TestCase):
    def setUp(self):
        """Runs before each test"""
        db.create_all()
        NoteColours.invalidate_cache()

        with db.Session() as session:
            track1_path = "testdata/isa.mp3"
            self.track1 = Tracks(session, **helpers.get_all_track_metadata(track1_path))

            track2_path = "testdata/mom.mp3"
            self.track2 = Tracks(session, **helpers.get_all_track_metadata(track2_path))

    def tearDown(self):
        """Runs after each test"""
        db.drop_all()

    def test_track_repr(self):
        with db.Session() as session:
            session.add(self.track1)
            _ = str(self.track1)

    def test_notecolours_get_colour(self):
        """Create a colour record and retrieve all colours"""

        note_colour = "#0bcdef"
        with db.Session() as session:
            NoteColours(session, substring="substring", colour=note_colour)

            records = NoteColours.get_all(session)
            assert len(records) == 1
            record = records[0]
            assert record.colour == note_colour

    def test_notecolours_get_all(self):
        """Create two colour records and retrieve them all"""

        note1_colour = "#1bcdef"
        note2_colour = "#20ff00"
        with db.Session() as session:
            NoteColours(session, substring="note1", colour=note1_colour)
            NoteColours(session, substring="note2", colour=note2_colour)

            records = NoteColours.get_all(session)
            assert len(records) == 2
            assert note1_colour in [n.colour for n in records]
            assert note2_colour in [n.colour for n in records]

    def test_notecolours_get_colour_none(self):
        note_colour = "#3bcdef"
        with db.Session() as session:
            NoteColours(session, substring="substring", colour=note_colour)

            result = NoteColours.get_colour(session, "xyz")
            assert result == ""

    def test_notecolours_get_colour_match(self):
        note_colour = "#4bcdef"
        with db.Session() as session:
            nc = NoteColours(session, substring="sub", colour=note_colour)
            assert nc

            result = NoteColours.get_colour(session, "The substring")
            assert result == note_colour

    def test_playdates_add_playdate(self):
        """Test playdate and last_played retrieval"""

        with db.Session() as session:
            session.add(self.track1)
            playdate = Playdates(session, self.track1.id)
            assert playdate
            # test repr
            _ = str(playdate)

            last_played = Playdates.last_played(session, self.track1.id)
            assert abs((playdate.lastplayed - last_played).total_seconds()) < 2

    def test_playdates_played_after(self):
        with db.Session() as session:
            session.add(self.track1)
            playdate = Playdates(session, self.track1.id)
            yesterday = dt.datetime.now() - dt.timedelta(days=1)
            played = Playdates.played_after(session, yesterday)

            assert len(played) == 1
            assert played[0] == playdate

    def test_playlist_create(self):
        TEMPLATE_NAME = "my template"

        with db.Session() as session:
            playlist = Playlists(session, "my playlist", template_id=0)
            assert playlist
            # test repr
            _ = str(playlist)

            # test clear tabs
            Playlists.clear_tabs(session, [playlist.id])

            # create template
            Playlists.save_as_template(session, playlist.id, TEMPLATE_NAME)

            # get all templates
            all_templates = Playlists.get_all_templates(session)
            assert len(all_templates) == 1
            # Save as template creates new playlist
            assert all_templates[0] != playlist
            # test delete playlist
            session.delete(playlist)

    def test_playlist_open_and_close(self):
        # We need a playlist
        with db.Session() as session:
            playlist = Playlists(session, "my playlist", template_id=0)

            assert len(Playlists.get_open(session)) == 0
            assert len(Playlists.get_closed(session)) == 1

            playlist.mark_open()

            assert len(Playlists.get_open(session)) == 1
            assert len(Playlists.get_closed(session)) == 0

            playlist.close(session)

            assert len(Playlists.get_open(session)) == 0
            assert len(Playlists.get_closed(session)) == 1

    def test_playlist_get_all_and_by_id(self):
        # We need two playlists
        p1_name = "playlist one"
        p2_name = "playlist two"
        with db.Session() as session:
            playlist1 = Playlists(session, p1_name, template_id=0)
            _ = Playlists(session, p2_name, template_id=0)

            all_playlists = Playlists.get_all(session)
            assert len(all_playlists) == 2
            assert p1_name in [p.name for p in all_playlists]
            assert p2_name in [p.name for p in all_playlists]
            assert session.get(Playlists, playlist1.id).name == p1_name

    def test_tracks_get_all_tracks(self):
        # Need two tracks

        with db.Session() as session:
            session.add(self.track1)
            session.add(self.track2)
            result = [a.path for a in Tracks.get_all(session)]
            assert self.track1.path in result
            assert self.track2.path in result

    def test_tracks_by_path(self):
        with db.Session() as session:
            session.add(self.track1)
            assert Tracks.get_by_path(session, self.track1.path) is self.track1

    def test_tracks_by_id(self):
        with db.Session() as session:
            session.add(self.track1)
            assert session.get(Tracks, self.track1.id) is self.track1

    def test_tracks_search_artists(self):
        track1_artist = "Fleetwood Mac"

        with db.Session() as session:
            session.add(self.track1)
            assert len(Tracks.search_artists(session, track1_artist)) == 1

    def test_tracks_search_titles(self):
        track1_title = "I'm So Afraid"

        with db.Session() as session:
            session.add(self.track1)
            assert len(Tracks.search_titles(session, track1_title)) == 1

    def test_repr(self):
        """Just check for error retrieving reprs"""

        with db.Session() as session:
            nc = NoteColours(session, substring="x", colour="x")
            _ = str(nc)

    def test_get_colour_1(self):
        """Test for errors in execution"""

        GOOD_STRING = "cantelope"
        BAD_STRING = "ericTheBee"
        SUBSTR = "ant"
        COLOUR = "blue"

        with db.Session() as session:
            nc1 = NoteColours(
                session, substring=SUBSTR, colour=COLOUR, is_casesensitive=True
            )

            session.commit()
            _ = nc1.get_colour(session, "")
            colour = nc1.get_colour(session, GOOD_STRING)
            assert colour == COLOUR

            colour = nc1.get_colour(session, BAD_STRING)
            assert colour == ""

    def test_get_colour_2(self):
        """Test for errors in execution"""

        GOOD_STRING = "cantelope"
        BAD_STRING = "ericTheBee"
        SUBSTR = "ant"
        COLOUR = "blue"

        with db.Session() as session:
            nc2 = NoteColours(
                session, substring=".*" + SUBSTR, colour=COLOUR, is_regex=True
            )
            session.commit()
            colour = nc2.get_colour(session, GOOD_STRING)
            assert colour == COLOUR

            colour = nc2.get_colour(session, BAD_STRING)
            assert colour == ""

    def test_get_colour_3(self):
        """Test for errors in execution"""

        GOOD_STRING = "cantelope"
        BAD_STRING = "ericTheBee"
        SUBSTR = "ant"
        COLOUR = "blue"

        with db.Session() as session:
            nc3 = NoteColours(
                session,
                substring=".*" + SUBSTR,
                colour=COLOUR,
                is_regex=True,
                is_casesensitive=True,
            )
            session.commit()

            colour = nc3.get_colour(session, GOOD_STRING)
            assert colour == COLOUR

            colour = nc3.get_colour(session, BAD_STRING)
            assert colour == ""

    def test_name_available(self):
        PLAYLIST_NAME = "a name"
        RENAME = "new name"

        with db.Session() as session:
            if Playlists.name_is_available(session, PLAYLIST_NAME):
                playlist = Playlists(session, PLAYLIST_NAME, template_id=0)
                assert playlist

            assert Playlists.name_is_available(session, PLAYLIST_NAME) is False

        playlist.rename(session, RENAME)

    def test_create_playlist_row(self):
        PLAYLIST_NAME = "a name"

        with db.Session() as session:
            if Playlists.name_is_available(session, PLAYLIST_NAME):
                playlist = Playlists(session=session, name=PLAYLIST_NAME, template_id=0)

            plr = PlaylistRows(session, playlist.id, 1)
            assert plr
            _ = str(plr)
            plr.append_note("a note")
            plr.append_note("another note")

    def test_delete_plr(self):
        PLAYLIST_NAME = "a name"

        with db.Session() as session:
            if Playlists.name_is_available(session, PLAYLIST_NAME):
                playlist = Playlists(session=session, name=PLAYLIST_NAME, template_id=0)

            plr = PlaylistRows(session, playlist.id, 1)
            assert plr
            PlaylistRows.delete_higher_rows(session, plr.playlist_id, 10)

            assert PlaylistRows.get_track_plr(session, 12, plr.playlist_id) is None
