# This file is part of hatch-tryton.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

import unittest
from textwrap import dedent
from typing import TYPE_CHECKING

from hatch_tryton.plugin import Author, TrytonMetadataHook, _get_authors

from .tools import with_temporay_directory

if TYPE_CHECKING or True:
    from pathlib import Path


class TestMetadata(unittest.TestCase):

    @with_temporay_directory
    def test_module_version(self, directory: Path):
        "Test module version"
        config = {}
        metadata = {
            'dynamic': ['version', 'dependencies'],
            }
        (directory / 'tryton.cfg').write_text(dedent("""\
                [tryton]
                version=1.0.0
                """))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual('1.0.0', metadata.get('version'))

    @with_temporay_directory
    def test_dependencies(self, directory: Path):
        "Test dependencies"
        config = {
            'dependencies': ['other-package > 1'],
            }
        metadata = {
            'dynamic': ['dependencies'],
            }
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual(
            ['other-package > 1'],
            metadata.get('dependencies', []))

    @with_temporay_directory
    def test_tryton_dependencies(self, directory: Path):
        "Test Tryton dependencies"
        config = {
            'tryton_dependencies': ['other-package'],
            }
        metadata = {
            'version': '1.0.0',
            'dynamic': ['dependencies'],
            }
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual(
            ['other-package >= 1.0, < 1.1'],
            metadata.get('dependencies', []))

    @with_temporay_directory
    def test_module_dependencies(self, directory: Path):
        "Test module dependencies"
        config = {}
        metadata = {
            'dynamic': ['dependencies'],
            }
        (directory / 'tryton.cfg').write_text(dedent("""\
                [tryton]
                version=1.0.0
                depends:
                    other_module
                """))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual([
                'trytond >= 1.0, < 1.1',
                'trytond_other_module >= 1.0, < 1.1',
                ],
            metadata.get('dependencies', []))

    @with_temporay_directory
    def test_base_module_dependencies(self, directory: Path):
        "Test base module dependencies"
        config = {}
        metadata = {
            'dynamic': ['dependencies'],
            }
        (directory / 'tryton.cfg').write_text(dedent("""\
                [tryton]
                version=1.0.0
                depends:
                    res
                    ir
                    tests
                """))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual(
            ['trytond >= 1.0, < 1.1'],
            metadata.get('dependencies', []))

    @with_temporay_directory
    def test_module_dependencies_prefix(self, directory: Path):
        "Test module dependencies with prefix"
        config = {
            'prefixes': {'other_module': 'organisation'},
            }
        metadata = {
            'dynamic': ['dependencies'],
            }
        (directory / 'tryton.cfg').write_text(dedent("""\
                [tryton]
                version=1.0.0
                depends:
                    other_module
                """))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual([
                'trytond >= 1.0, < 1.1',
                'organisation_other_module >= 1.0, < 1.1',
                ],
            metadata.get('dependencies', []))

    @with_temporay_directory
    def test_dependencies_not_dynamic(self, directory: Path):
        "Test dependencies not dynamic"
        config = {
            'dependencies': ['other_module'],
            }
        metadata = {
            'dynamic': ['optional-dependencies'],
            }
        hook = TrytonMetadataHook(directory, config)
        with self.assertRaisesRegex(ValueError, r"dependencies.*dynamic"):
            hook.update(metadata)

    @with_temporay_directory
    def test_optional_dependencies(self, directory: Path):
        "Test optional-dependencies"
        config = {
            'optional-dependencies': {
                'option': ['other-package > 1'],
                }
            }
        metadata = {
            'dynamic': ['optional-dependencies'],
            }
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual(
            ['other-package > 1'],
            metadata.get('optional-dependencies', {}).get('option', []))

    @with_temporay_directory
    def test_tryton_optional_dependencies(self, directory: Path):
        "Test Tryton optional-dependencies"
        config = {
            'optional-dependencies': {
                'option': ['other-package > 1'],
                },
            'tryton-optional-dependencies': {
                'option': ['module'],
                }
            }
        metadata = {
            'version': '1.0.0',
            'dynamic': ['optional-dependencies'],
            }
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual(
            ['other-package > 1', 'module >= 1.0, < 1.1'],
            metadata.get('optional-dependencies', {}).get('option', []))

    @with_temporay_directory
    def test_module_extra_dependencies(self, directory: Path):
        "Test module extra dependencies"
        config = {}
        metadata = {
            'dynamic': ['dependencies', 'optional-dependencies'],
            }
        (directory / 'tryton.cfg').write_text(dedent("""\
                [tryton]
                version=1.0.0
                extras_depend:
                    other_module
                """))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual({
                'test': ['trytond_other_module >= 1.0, < 1.1'],
                },
            metadata.get('optional-dependencies', {}))

    @with_temporay_directory
    def test_module_extra__tryton_optional_dependencies(self, directory: Path):
        "Test module extra and Tryton optional dependencies"
        config = {
            'tryton-optional-dependencies': {
                'test': ['module'],
                },
            }
        metadata = {
            'dynamic': ['dependencies', 'optional-dependencies'],
            }
        (directory / 'tryton.cfg').write_text(dedent("""\
                [tryton]
                version=1.0.0
                extras_depend:
                    other_module
                """))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual({
                'test': [
                    'trytond_other_module >= 1.0, < 1.1',
                    'module >= 1.0, < 1.1',
                    ],
                },
            metadata.get('optional-dependencies', {}))

    @with_temporay_directory
    def test_optional_dependencies_not_dynamic(self, directory: Path):
        "Test optional-dependencies not dynamic"
        config = {
            'optional-dependencies': {
                'option': ['other_module'],
                },
            }
        metadata = {
            'dynamic': [],
            }
        hook = TrytonMetadataHook(directory, config)
        with self.assertRaisesRegex(
                ValueError, r"optional-dependencies.*dynamic"):
            hook.update(metadata)

    @with_temporay_directory
    def test_readme(self, directory: Path):
        "Test readme"
        config = {
            'readme': 'README.rst',
            }
        metadata = {
            'dynamic': ['readme'],
            }
        (directory / 'README.rst').write_text(dedent("""\
                Module
                ======

                description

                .. toctree::
                   :maxdepth: 2

                   setup
                   reference
                """))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual({
                'content-type': 'text/x-rst',
                'text': dedent("""\
                        Module
                        ======

                        description

                        """),
                }, metadata.get('readme', {}))

    @with_temporay_directory
    def test_readme_markdown(self, directory: Path):
        "Test readme"
        config = {
            'readme': 'README.md',
            }
        metadata = {
            'dynamic': ['readme'],
            }
        (directory / 'README.md').write_text(dedent("""\
                Module
                ======

                description
                """))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual({
                'content-type': 'text/markdown',
                'text': dedent("""\
                        Module
                        ======

                        description
                        """),
                }, metadata.get('readme', {}))

    @with_temporay_directory
    def test_readme_unknown_type(self, directory: Path):
        "Test readme"
        config = {
            'readme': 'README.txt',
            }
        metadata = {
            'dynamic': ['readme'],
            }
        (directory / 'README.txt').write_text('')
        hook = TrytonMetadataHook(directory, config)
        with self.assertRaisesRegex(ValueError, r"readme.*\.txt"):
            hook.update(metadata)

    @with_temporay_directory
    def test_readme_not_dynamic(self, directory: Path):
        "Test readme not dynamic"
        config = {
            'readme': 'README.md',
            }
        metadata = {
            'dynamic': [],
            }
        (directory / 'README.md').write_text('')
        hook = TrytonMetadataHook(directory, config)
        with self.assertRaisesRegex(ValueError, r"readme.*dynamic"):
            hook.update(metadata)

    @with_temporay_directory
    def test_authors_from_copyright(self, directory: Path):
        "Test authors from copyright file"
        config = {
            'copyright': 'COPYRIGHT',
            }
        metadata = {
            'dynamic': ['authors'],
            }
        (directory / 'COPYRIGHT').write_text(dedent("""\
                Copyright (C) 9999 John Doe
                Copyright (C) Foo

                Text"""))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual(
            [{'name': "John Doe", 'email': ''}],
            metadata.get('authors'))

    @with_temporay_directory
    def test_authors_from_copyright_not_dynamic(self, directory: Path):
        "Test authors from copyright file not dynamic"
        config = {
            'copyright': 'COPYRIGHT',
            }
        metadata = {
            'authors': [{'name': "Jane Doe", 'email': ''}],
            }
        (directory / 'COPYRIGHT').write_text(dedent("""\
                Copyright (C) 9999 John Doe

                Text"""))
        hook = TrytonMetadataHook(directory, config)
        hook.update(metadata)
        self.assertEqual(
            [{'name': "Jane Doe", 'email': ''}],
            metadata.get('authors'))

    @with_temporay_directory
    def test_get_authors(self, directory: Path):
        "Test get authors from copyright file"
        (directory / 'COPYRIGHT').write_text(dedent("""\
                Copyright (C) 9999 John Doe
                Copyright (C) 0000-9999 Jane Doe
                Copyright (C) 9999 John Doe <john.doe@example.com>
                Copyright (C) 9999 <email@example.com>
                junk"""))
        authors = list(_get_authors(directory, 'COPYRIGHT'))

        self.assertEqual([
                Author("John Doe", ''),
                Author("Jane Doe", ''),
                Author("John Doe", 'john.doe@example.com'),
                Author('', 'email@example.com'),
                ],
            authors)
