import os
import pytest
import shutil
from calculate.templates.format.contents_format import ContentsFormat
from calculate.utils.package import PackageAtomName, Version, Package
from calculate.utils.files import join_paths


TESTFILES_PATH = os.path.join(os.getcwd(),
                              'tests/templates/format/testfiles/contents')


@pytest.mark.contents
class TestExecutingFormat:
    def test_copy_testfiles(self):
        entries = os.scandir(TESTFILES_PATH)
        for root_entry in entries:
            if root_entry.path.endswith('.backup'):
                shutil.copytree(root_entry.path,
                                root_entry.path.rstrip('.backup'),
                                symlinks=True)

    def test_if_template_of_the_contents_format_contains_some_files_to_add_directory_to_add_and_link_to_add_and_some_files_is_listed_using_glob_symbols__all_files_links_and_directories_are_added_to_the_target_package(self):
        chroot_path = os.path.join(TESTFILES_PATH, 'root_0')
        test_package_name = PackageAtomName(
                              {'pkg_path':
                               os.path.join(
                                  chroot_path,
                                  'var/db/pkg/test-category/test-package-1.0'),
                               'version': Version('1.0')})

        template_text = '''
        test-category/test-package /etc/dir_0/*

        test-category/test-package /etc/dir_1/file_0

        test-category/test-package /etc/dir_2

        test-category/test-package /etc/dir_3/link_0
        '''
        result_contents = '''dir /etc
dir /etc/dir_0
obj /etc/dir_0/file_0 c585be6f171462940b44af994a54040d 1593525253
obj /etc/dir_0/file_1 b4ff15ea7028891a83392b490d676622 {0}
dir /etc/dir_1
obj /etc/dir_1/file_0 b4ff15ea7028891a83392b490d676622 {1}
dir /etc/dir_2
dir /etc/dir_3
sym /etc/dir_3/link_0 -> ../dir_1/file_0 {2}
'''.format(int(os.lstat(join_paths(chroot_path,
                                   '/etc/dir_0/file_1')).st_mtime),
           int(os.lstat(join_paths(chroot_path,
                                   '/etc/dir_1/file_0')).st_mtime),
           int(os.lstat(join_paths(chroot_path,
                                   '/etc/dir_3/link_0')).st_mtime))

        contents_format = ContentsFormat(template_text, '/path/to/template')
        contents_format.execute_format('target/path', chroot_path=chroot_path)

        test_package = Package(test_package_name,
                               chroot_path=chroot_path)

        assert '/etc/dir_0/file_0' in test_package
        assert '/etc/dir_0/file_1' in test_package

        assert '/etc/dir_1' in test_package
        assert '/etc/dir_1/file_0' in test_package

        assert '/etc/dir_2' in test_package

        assert '/etc/dir_3' in test_package
        assert '/etc/dir_3/link_0' in test_package

        with open(os.path.join(
                      chroot_path,
                      'var/db/pkg/test-category/test-package-1.0/CONTENTS'),
                  'r') as test_contents:
            assert test_contents.read() == result_contents

    def test_if_template_of_the_contents_format_contains_some_files_to_remove_directory_to_remove_and_link_to_remove_and_some_files_is_listed_using_glob_symbols__all_files_links_and_directories_are_removed_from_the_target_package(self):
        chroot_path = os.path.join(TESTFILES_PATH, 'root_1')
        test_package_name = PackageAtomName(
                              {'pkg_path':
                               os.path.join(
                                  chroot_path,
                                  'var/db/pkg/test-category/test-package-1.0'),
                               'version': Version('1.0')})
        template_text = '''
        !test-category/test-package /etc/dir_0/file_1

        !test-category/test-package /etc/dir_1/*

        !test-category/test-package /etc/dir_2/

        !test-category/test-package /etc/dir_3/link_0
        '''
        result_contents = '''dir /etc
dir /etc/dir_0
obj /etc/dir_0/file_0 c585be6f171462940b44af994a54040d 1593525253
dir /etc/dir_1
dir /etc/dir_3
'''

        contents_format = ContentsFormat(template_text, '/path/to/template')
        contents_format.execute_format('target/path', chroot_path=chroot_path)

        test_package = Package(test_package_name,
                               chroot_path=chroot_path)

        assert '/etc/dir_0/file_0' in test_package
        assert '/etc/dir_0/file_1' not in test_package

        assert '/etc/dir_1' in test_package
        assert '/etc/dir_1/file_0' not in test_package
        assert '/etc/dir_1/file_1' not in test_package

        assert '/etc/dir_3' in test_package
        assert '/etc/dir_3/link_0' not in test_package

        with open(os.path.join(
                      chroot_path,
                      'var/db/pkg/test-category/test-package-1.0/CONTENTS'),
                  'r') as test_contents:
            assert test_contents.read() == result_contents

    def test_if_template_of_the_contents_format_contains_some_files_to_move_from_a_source_package_to_a_target_package_directory_to_move_and_link_to_move_and_some_files_is_listed_using_glob_symbols__all_files_links_and_directories_are_moved_from_the_source_package_to_the_target_package(self):
        chroot_path = os.path.join(TESTFILES_PATH, 'root_2')
        test_package_name = PackageAtomName(
                              {'pkg_path':
                               os.path.join(
                                chroot_path,
                                'var/db/pkg/test-category/test-package-1.0'),
                               'version': Version('1.0')})
        other_package_name = PackageAtomName(
                              {'pkg_path':
                               os.path.join(
                                chroot_path,
                                'var/db/pkg/test-category/other-package-1.1'),
                               'version': Version('1.1')})
        other_package = Package(other_package_name,
                                chroot_path=chroot_path)
        template_text = '''
test-category/test-package, test-category/other-package /etc/dir_0/file_0
test-category/other-package, test-category/test-package /etc/dir_0/file_1

test-category/test-package, test-category/other-package /etc/dir_1/file_[1,3]
test-category/other-package, test-category/test-package /etc/dir_1/file_[0,2]

test-category/test-package, test-category/other-package /etc/dir_3/
test-category/other-package, test-category/test-package /etc/dir_4/

test-category/test-package, test-category/other-package /etc/dir_5/link_0
test-category/other-package, test-category/test-package /etc/dir_5/link_1
'''
        test_result = '''dir /etc
dir /etc/dir_0
obj /etc/dir_0/file_1 c585be6f171462940b44af994a54040d 1593525253
dir /etc/dir_1
obj /etc/dir_1/file_0 b4ff15ea7028891a83392b490d676622 1601987083
obj /etc/dir_1/file_2 b4ff15ea7028891a83392b490d676622 1601987083
obj /etc/dir_1/file_4 b4ff15ea7028891a83392b490d676622 1601987083
dir /etc/dir_4
obj /etc/dir_4/file_0 b4ff15ea7028891a83392b490d676622 1601982062
dir /etc/dir_5
sym /etc/dir_5/link_1 -> ../dir_1/file_0 1601991426
'''
        other_result = '''dir /etc
dir /etc/dir_0
obj /etc/dir_0/file_0 c585be6f171462940b44af994a54040d 1593525253
dir /etc/dir_1
obj /etc/dir_1/file_1 b4ff15ea7028891a83392b490d676622 1601987083
obj /etc/dir_1/file_3 b4ff15ea7028891a83392b490d676622 1601987083
obj /etc/dir_1/file_5 b4ff15ea7028891a83392b490d676622 1601987083
dir /etc/dir_3
obj /etc/dir_3/file_0 b4ff15ea7028891a83392b490d676622 1601982062
dir /etc/dir_5
sym /etc/dir_5/link_0 -> ../dir_1/file_0 1601991426
'''

        contents_format = ContentsFormat(template_text, '/path/to/template')
        contents_format.execute_format('target/path', chroot_path=chroot_path)

        test_package = Package(test_package_name,
                               chroot_path=chroot_path)
        other_package = Package(other_package_name,
                                chroot_path=chroot_path)

        assert '/etc/dir_0/file_0' not in test_package
        assert '/etc/dir_0/file_1' not in other_package
        assert '/etc/dir_0/file_1' in test_package
        assert '/etc/dir_0/file_0' in other_package

        assert '/etc/dir_1/file_1' not in test_package
        assert '/etc/dir_1/file_3' not in test_package
        assert '/etc/dir_1/file_0' not in other_package
        assert '/etc/dir_1/file_2' not in other_package

        assert '/etc/dir_1/file_0' in test_package
        assert '/etc/dir_1/file_2' in test_package
        assert '/etc/dir_1/file_4' in test_package
        assert '/etc/dir_1/file_1' in other_package
        assert '/etc/dir_1/file_3' in other_package
        assert '/etc/dir_1/file_5' in other_package

        assert '/etc/dir_3' not in test_package
        assert '/etc/dir_3/file_0' not in test_package
        assert '/etc/dir_4' not in other_package
        assert '/etc/dir_4/file_0' not in other_package
        assert '/etc/dir_4' in test_package
        assert '/etc/dir_4/file_0' in test_package
        assert '/etc/dir_3' in other_package
        assert '/etc/dir_3/file_0' in other_package

        assert '/etc/dir_5/link_0' not in test_package
        assert '/etc/dir_5/link_1' not in other_package
        assert '/etc/dir_5/link_1' in test_package
        assert '/etc/dir_5/link_0' in other_package

        with open(test_package_name.contents_path, 'r') as test_contents:
            assert test_contents.read() == test_result

        with open(other_package_name.contents_path,
                  'r') as other_contents:
            assert other_contents.read() == other_result

    def test_remove_testfiles(self):
        entries = os.scandir('./tests/templates/format/testfiles/contents')
        for root_entry in entries:
            if root_entry.path.endswith('.backup'):
                shutil.rmtree(root_entry.path.rstrip('.backup'))
