# Copyright 2012 Christoph Reiter
#           2020 Nick Boultbee
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
from unittest.mock import Mock

import quodlibet.config
from quodlibet import app
from quodlibet.formats import AudioFile
from quodlibet.plugins.editing import EditTagsPlugin
from quodlibet.qltk.edittags import (SplitValues, SplitDisc, SplitTitle,
                                     SplitArranger, AddTagDialog,
                                     AudioFileGroup, EditTags, ListEntry,
                                     Comment, EditTagsPluginHandler)
from quodlibet.qltk.properties import SongProperties
from tests import TestCase, init_fake_app, destroy_fake_app


class DummyEditPlugin(EditTagsPlugin):
    activations = []

    def activated(self, tag, value):
        self.activations.append((tag, value))
        return super().activated(tag, value)


class TEditTags(TestCase):
    def setUp(self):
        init_fake_app()
        quodlibet.config.init()

    def tearDown(self):
        quodlibet.config.quit()
        destroy_fake_app()

    def test_items(self):
        SplitValues("foo", "bar").destroy()
        SplitDisc("foo", "bar").destroy()
        SplitTitle("foo", "bar").destroy()
        SplitArranger("foo", "bar").destroy()

    def test_addtag_dialog(self):
        AddTagDialog(None, ["artist"], app.library).destroy()

    def test_edit_tags_starts(self):
        props = SongProperties(app.library, [], quodlibet.app.window)
        EditTags(props, app.library)

    def test_edit_tags_popup_menu(self):
        song = AudioFile({"~filename": "/dev/null", "artist": "Person",
                          "album": "Dj Bars of FOO"})
        props = SongProperties(app.library, [song], app.window)
        box = EditTags(props, app.library)

        # Add a fake plugin
        plugin_cls = DummyEditPlugin
        box.handler = Mock(EditTagsPluginHandler)
        box.handler.plugins = [plugin_cls]
        model = box._view.get_model()

        # Make sure there's a row
        tag, value = "artist", song("artist")
        entry = ListEntry(tag, Comment(value))
        model.append(row=[entry])

        box._group_info = AudioFileGroup([song])
        box._view.select_by_func(lambda _: True)
        # Prevent weird mouse stuff failing in tests
        box._view.ensure_popup_selection = lambda: False
        box._popup_menu(box._view, props)
        box.show()
        assert plugin_cls.activations == [(tag, value)]


class GroupSong(AudioFile):

    def __init__(self, can_multiple=True, can_change=True, cant_change=[]):
        self._can_multiple = can_multiple
        self._can_change = can_change
        self._cant_change = cant_change

    def can_multiple_values(self, key=None):
        if key is None:
            return self._can_multiple
        if self._can_multiple is True:
            return True
        return key in self._can_multiple

    def can_change(self, key=None):
        if key is None:
            return self._can_change
        if self._can_change is True:
            return key not in self._cant_change
        return key in self._can_change


class TAudioFileGroup(TestCase):

    def test_multiple_values(self):
        group = AudioFileGroup([GroupSong(True), GroupSong(True)])
        self.assertTrue(group.can_multiple_values() is True)
        self.assertTrue(group.can_multiple_values("foo") is True)

        group = AudioFileGroup([GroupSong(["ha"]), GroupSong(True)])
        self.assertEqual(group.can_multiple_values(), {"ha"})
        self.assertFalse(group.can_multiple_values("foo"))
        self.assertTrue(group.can_multiple_values("ha"))

        group = AudioFileGroup([GroupSong(["foo", "ha"]), GroupSong(["ha"])])
        self.assertEqual(group.can_multiple_values(), {"ha"})
        self.assertFalse(group.can_multiple_values("foo"))
        self.assertTrue(group.can_multiple_values("ha"))

    def test_can_change(self):
        group = AudioFileGroup(
            [GroupSong(can_change=True), GroupSong(can_change=True)])
        self.assertTrue(group.can_change() is True)
        self.assertTrue(group.can_change("foo") is True)

        group = AudioFileGroup(
            [GroupSong(can_change=["foo", "ha"]),
             GroupSong(can_change=["ha"])])
        self.assertEqual(group.can_change(), {"ha"})
        self.assertFalse(group.can_change("foo"))
        self.assertTrue(group.can_change("ha"))

        group = AudioFileGroup([GroupSong(), GroupSong(cant_change=["baz"])])
        self.assertTrue(group.can_change())
        self.assertFalse(group.can_change("baz"))
