# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
#
# Copyright (C) 2019-2020  Philipp Wolfer
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.


from mutagen.asf import ASFByteArrayAttribute

from test.picardtestcase import (
    PicardTestCase,
    create_fake_png,
)

from picard.formats import (
    asf,
    ext_to_format,
)

from .common import (
    CommonTests,
    load_metadata,
    load_raw,
    save_metadata,
    save_raw,
    skipUnlessTestfile,
)
from .coverart import CommonCoverArtTests


# prevent unittest to run tests in those classes
class CommonAsfTests:

    class AsfTestCase(CommonTests.TagFormatsTestCase):

        def test_supports_tag(self):
            fmt = ext_to_format(self.testfile_ext[1:])
            self.assertTrue(fmt.supports_tag('copyright'))
            self.assertTrue(fmt.supports_tag('compilation'))
            self.assertTrue(fmt.supports_tag('bpm'))
            self.assertTrue(fmt.supports_tag('djmixer'))
            self.assertTrue(fmt.supports_tag('discnumber'))
            self.assertTrue(fmt.supports_tag('lyrics:lead'))
            self.assertTrue(fmt.supports_tag('~length'))
            for tag in self.replaygain_tags.keys():
                self.assertTrue(fmt.supports_tag(tag))

        @skipUnlessTestfile
        def test_ci_tags_preserve_case(self):
            # Ensure values are not duplicated on repeated save and are saved
            # case preserving.
            tags = {
                'Replaygain_Album_Peak': '-6.48 dB'
            }
            save_raw(self.filename, tags)
            loaded_metadata = load_metadata(self.filename)
            loaded_metadata['replaygain_album_peak'] = '1.0'
            save_metadata(self.filename, loaded_metadata)
            raw_metadata = load_raw(self.filename)
            self.assertIn('Replaygain_Album_Peak', raw_metadata)
            self.assertEqual(raw_metadata['Replaygain_Album_Peak'][0], loaded_metadata['replaygain_album_peak'])
            self.assertEqual(1, len(raw_metadata['Replaygain_Album_Peak']))
            self.assertNotIn('REPLAYGAIN_ALBUM_PEAK', raw_metadata)

        def _test_invalid_picture(self, invalid_picture_data):
            png_data = create_fake_png(b'x')
            tags = {
                'WM/Picture': [
                    ASFByteArrayAttribute(invalid_picture_data),
                    ASFByteArrayAttribute(
                        asf.pack_image("image/png", png_data)
                    )
                ]
            }
            save_raw(self.filename, tags)
            metadata = load_metadata(self.filename)
            self.assertEqual(1, len(metadata.images))
            self.assertEqual(png_data, metadata.images[0].data)

        @skipUnlessTestfile
        def test_ignore_invalid_wm_picture(self):
            # A picture that cannot be unpacked
            self._test_invalid_picture(b'notapicture')


class ASFTest(CommonAsfTests.AsfTestCase):
    testfile = 'test.asf'
    supports_ratings = True
    expected_info = {
        'length': 92,
        '~channels': '2',
        '~sample_rate': '44100',
        '~bitrate': '128.0',
    }


class WMATest(CommonAsfTests.AsfTestCase):
    testfile = 'test.wma'
    supports_ratings = True
    expected_info = {
        'length': 139,
        '~channels': '2',
        '~sample_rate': '44100',
        '~bitrate': '64.0',
    }
    unexpected_info = ['~video']


class WMVTest(CommonAsfTests.AsfTestCase):
    testfile = 'test.wmv'
    supports_ratings = True
    expected_info = {
        'length': 565,
        '~channels': '2',
        '~sample_rate': '44100',
        '~bitrate': '128.0',
        '~video': '1',
    }


class AsfUtilTest(PicardTestCase):
    test_cases = [
        # Empty MIME, description and data
        (('', b'', 2, ''), b'\x02\x00\x00\x00\x00\x00\x00\x00\x00'),
        # MIME, description set, 1 byte data
        (('M', b'x', 2, 'D'), b'\x02\x01\x00\x00\x00M\x00\x00\x00D\x00\x00\x00x'),
        # Empty MIME and description, 3 byte data
        (('', b'abc', 0, ''), b'\x00\x03\x00\x00\x00\x00\x00\x00\x00abc'),
    ]

    def test_pack_and_unpack_image(self):
        mime = 'image/png'
        image_data = create_fake_png(b'x')
        image_type = 4
        description = 'testing'
        tag_data = asf.pack_image(mime, image_data, image_type, description)
        expected_length = 5 + 2 * len(mime) + 2 + 2 * len(description) + 2 + len(image_data)
        self.assertEqual(tag_data[0], image_type)
        self.assertEqual(len(tag_data), expected_length)
        self.assertEqual(image_data, tag_data[-len(image_data):])

        unpacked = asf.unpack_image(tag_data)
        self.assertEqual(mime, unpacked[0])
        self.assertEqual(image_data, unpacked[1])
        self.assertEqual(image_type, unpacked[2])
        self.assertEqual(description, unpacked[3])

    def test_pack_image(self):
        for args, expected in self.test_cases:
            self.assertEqual(expected, asf.pack_image(*args))

    def test_unpack_image(self):
        for expected, packed in self.test_cases:
            self.assertEqual(expected, asf.unpack_image(packed))

    def test_unpack_image_value_errors(self):
        self.assertRaisesRegex(ValueError, "unpack_from requires a buffer of at least 5 bytes",
                               asf.unpack_image, b'')
        self.assertRaisesRegex(ValueError, "unpack_from requires a buffer of at least 5 bytes",
                               asf.unpack_image, b'\x02\x01\x00\x00')
        self.assertRaisesRegex(ValueError, "mime: missing data",
                               asf.unpack_image, b'\x00\x00\x00\x00\x00')
        self.assertRaisesRegex(ValueError, "mime: missing data",
                               asf.unpack_image, b'\x04\x19\x00\x00\x00a\x00')
        self.assertRaisesRegex(ValueError, "desc: missing data",
                               asf.unpack_image, b'\x04\x19\x00\x00\x00a\x00\x00\x00a\x00')
        self.assertRaisesRegex(ValueError, "image data size mismatch",
                               asf.unpack_image, b'\x04\x19\x00\x00\x00a\x00\x00\x00a\x00\x00\x00x')


class AsfCoverArtTest(CommonCoverArtTests.CoverArtTestCase):
    testfile = 'test.asf'


class WmaCoverArtTest(CommonCoverArtTests.CoverArtTestCase):
    testfile = 'test.wma'
