from __future__ import unicode_literals

import os
import unittest

from mopidy import exceptions
from mopidy.audio import scan
from mopidy.models import Track, Artist, Album
from mopidy.utils import path as path_lib

from tests import path_to_data_dir


class FakeGstDate(object):
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day


class TranslatorTest(unittest.TestCase):
    def setUp(self):
        self.data = {
            'uri': 'uri',
            'album': 'albumname',
            'track-number': 1,
            'artist': 'name',
            'composer': 'composer',
            'performer': 'performer',
            'album-artist': 'albumartistname',
            'title': 'trackname',
            'track-count': 2,
            'album-disc-number': 2,
            'album-disc-count': 3,
            'date': FakeGstDate(2006, 1, 1,),
            'container-format': 'ID3 tag',
            'genre': 'genre',
            'duration': 4531000000,
            'comment': 'comment',
            'musicbrainz-trackid': 'mbtrackid',
            'musicbrainz-albumid': 'mbalbumid',
            'musicbrainz-artistid': 'mbartistid',
            'musicbrainz-albumartistid': 'mbalbumartistid',
            'mtime': 1234,
        }

        self.album = {
            'name': 'albumname',
            'num_tracks': 2,
            'num_discs': 3,
            'musicbrainz_id': 'mbalbumid',
        }

        self.artist_single = {
            'name': 'name',
            'musicbrainz_id': 'mbartistid',
        }

        self.artist_multiple = {
            'name': ['name1', 'name2'],
            'musicbrainz_id': 'mbartistid',
        }

        self.artist = self.artist_single

        self.composer_single = {
            'name': 'composer',
        }

        self.composer_multiple = {
            'name': ['composer1', 'composer2'],
        }

        self.composer = self.composer_single

        self.performer_single = {
            'name': 'performer',
        }

        self.performer_multiple = {
            'name': ['performer1', 'performer2'],
        }

        self.performer = self.performer_single

        self.albumartist = {
            'name': 'albumartistname',
            'musicbrainz_id': 'mbalbumartistid',
        }

        self.track = {
            'uri': 'uri',
            'name': 'trackname',
            'date': '2006-01-01',
            'genre': 'genre',
            'track_no': 1,
            'disc_no': 2,
            'comment': 'comment',
            'length': 4531,
            'musicbrainz_id': 'mbtrackid',
            'last_modified': 1234,
        }

    def build_track(self):
        if self.albumartist:
            self.album['artists'] = [Artist(**self.albumartist)]
        self.track['album'] = Album(**self.album)

        if ('name' in self.artist
                and not isinstance(self.artist['name'], basestring)):
            self.track['artists'] = [Artist(name=artist)
                                     for artist in self.artist['name']]
        else:
            self.track['artists'] = [Artist(**self.artist)]

        if ('name' in self.composer
                and not isinstance(self.composer['name'], basestring)):
            self.track['composers'] = [Artist(name=artist)
                                       for artist in self.composer['name']]
        else:
            self.track['composers'] = [Artist(**self.composer)] \
                if self.composer else ''

        if ('name' in self.performer
                and not isinstance(self.performer['name'], basestring)):
            self.track['performers'] = [Artist(name=artist)
                                        for artist in self.performer['name']]
        else:
            self.track['performers'] = [Artist(**self.performer)] \
                if self.performer else ''

        return Track(**self.track)

    def check(self):
        expected = self.build_track()
        actual = scan.audio_data_to_track(self.data)
        self.assertEqual(expected, actual)

    def test_basic_data(self):
        self.check()

    def test_missing_track_number(self):
        del self.data['track-number']
        del self.track['track_no']
        self.check()

    def test_missing_track_count(self):
        del self.data['track-count']
        del self.album['num_tracks']
        self.check()

    def test_missing_track_name(self):
        del self.data['title']
        del self.track['name']
        self.check()

    def test_missing_track_musicbrainz_id(self):
        del self.data['musicbrainz-trackid']
        del self.track['musicbrainz_id']
        self.check()

    def test_missing_album_name(self):
        del self.data['album']
        del self.album['name']
        self.check()

    def test_missing_album_musicbrainz_id(self):
        del self.data['musicbrainz-albumid']
        del self.album['musicbrainz_id']
        self.check()

    def test_missing_artist_name(self):
        del self.data['artist']
        del self.artist['name']
        self.check()

    def test_missing_composer_name(self):
        del self.data['composer']
        del self.composer['name']
        self.check()

    def test_multiple_track_composers(self):
        self.data['composer'] = ['composer1', 'composer2']
        self.composer = self.composer_multiple
        self.check()

    def test_multiple_track_performers(self):
        self.data['performer'] = ['performer1', 'performer2']
        self.performer = self.performer_multiple
        self.check()

    def test_missing_performer_name(self):
        del self.data['performer']
        del self.performer['name']
        self.check()

    def test_missing_artist_musicbrainz_id(self):
        del self.data['musicbrainz-artistid']
        del self.artist['musicbrainz_id']
        self.check()

    def test_multiple_track_artists(self):
        self.data['artist'] = ['name1', 'name2']
        self.data['musicbrainz-artistid'] = 'mbartistid'
        self.artist = self.artist_multiple
        self.check()

    def test_missing_album_artist(self):
        del self.data['album-artist']
        del self.albumartist['name']
        self.check()

    def test_missing_album_artist_musicbrainz_id(self):
        del self.data['musicbrainz-albumartistid']
        del self.albumartist['musicbrainz_id']
        self.check()

    def test_missing_genre(self):
        del self.data['genre']
        del self.track['genre']
        self.check()

    def test_missing_date(self):
        del self.data['date']
        del self.track['date']
        self.check()

    def test_invalid_date(self):
        self.data['date'] = FakeGstDate(65535, 1, 1)
        del self.track['date']
        self.check()

    def test_missing_comment(self):
        del self.data['comment']
        del self.track['comment']
        self.check()


class ScannerTest(unittest.TestCase):
    def setUp(self):
        self.errors = {}
        self.data = {}

    def find(self, path):
        media_dir = path_to_data_dir(path)
        for path in path_lib.find_files(media_dir):
            yield os.path.join(media_dir, path)

    def scan(self, paths):
        scanner = scan.Scanner()
        for path in paths:
            uri = path_lib.path_to_uri(path)
            key = uri[len('file://'):]
            try:
                self.data[key] = scanner.scan(uri)
            except exceptions.ScannerError as error:
                self.errors[key] = error

    def check(self, name, key, value):
        name = path_to_data_dir(name)
        self.assertEqual(self.data[name][key], value)

    def test_data_is_set(self):
        self.scan(self.find('scanner/simple'))
        self.assert_(self.data)

    def test_errors_is_not_set(self):
        self.scan(self.find('scanner/simple'))
        self.assert_(not self.errors)

    def test_uri_is_set(self):
        self.scan(self.find('scanner/simple'))
        self.check(
            'scanner/simple/song1.mp3', 'uri',
            'file://%s' % path_to_data_dir('scanner/simple/song1.mp3'))
        self.check(
            'scanner/simple/song1.ogg', 'uri',
            'file://%s' % path_to_data_dir('scanner/simple/song1.ogg'))

    def test_duration_is_set(self):
        self.scan(self.find('scanner/simple'))
        self.check('scanner/simple/song1.mp3', 'duration', 4680000000)
        self.check('scanner/simple/song1.ogg', 'duration', 4680000000)

    def test_artist_is_set(self):
        self.scan(self.find('scanner/simple'))
        self.check('scanner/simple/song1.mp3', 'artist', 'name')
        self.check('scanner/simple/song1.ogg', 'artist', 'name')

    def test_album_is_set(self):
        self.scan(self.find('scanner/simple'))
        self.check('scanner/simple/song1.mp3', 'album', 'albumname')
        self.check('scanner/simple/song1.ogg', 'album', 'albumname')

    def test_track_is_set(self):
        self.scan(self.find('scanner/simple'))
        self.check('scanner/simple/song1.mp3', 'title', 'trackname')
        self.check('scanner/simple/song1.ogg', 'title', 'trackname')

    def test_nonexistant_dir_does_not_fail(self):
        self.scan(self.find('scanner/does-not-exist'))
        self.assert_(not self.errors)

    def test_other_media_is_ignored(self):
        self.scan(self.find('scanner/image'))
        self.assert_(self.errors)

    def test_log_file_that_gst_thinks_is_mpeg_1_is_ignored(self):
        self.scan([path_to_data_dir('scanner/example.log')])
        self.assert_(self.errors)

    def test_empty_wav_file_is_ignored(self):
        self.scan([path_to_data_dir('scanner/empty.wav')])
        self.assert_(self.errors)

    @unittest.SkipTest
    def test_song_without_time_is_handeled(self):
        pass
