import configparser
import os
from pathlib import Path

import svn_backup as svnbck_mod
import backup as bckup
from backup import DEFAULT_SCHEMA_SECTION, COPY_SCHEMA_SECTION, RSYNC_SCHEMA_SECTION
from svn_backup import SvnBackup
from utils.config_parse_helper import ConfigSchema

SVN_TEST_CONFIG = os.path.join(os.path.dirname(__file__), './testing/svn_test.config')


class TestArguments(object):

    def assert_defaults(self, sb: SvnBackup):

        assert sb.default_dict == \
            { 'backup_paths' :  [ '/export/ippops4.0/backups/svn_backups'
                                , '/data/ippops3.0/backups/svn_backups'
                                , '/data/ippops5.0/backups/svn_backups'
                                ]
            , 'source_machine' : 'ippops4'
            , 'verbose' : False
            }
        assert sb.copy_dict == \
            { 'sources' : ['/etc/apache2/mods-enabled/dav_svn.conf']
            , 'additional_args' : ['-v']
            }
        assert sb.rsync_dict == \
            { 'sources' : ['/export/ippops4.0/svnroot']
            , 'additional_args' : ['-a', '--delete-after']
            }

    def test_load_default_config_file(self):
        sb = SvnBackup(config_file=SVN_TEST_CONFIG)
        self.assert_defaults(sb)


class TestSvnCopy(object):
    """Simple inherit of base class Backup"""

    # Setup config
    def test_copy(self, tmpdir):
        backup_1_path = os.path.join(tmpdir, "backup_1_path")
        backup_2_path = os.path.join(tmpdir, "backup_2_path")
        config = configparser.ConfigParser()
        config['DEFAULT'] = \
            { 'backup_paths' :  f"{backup_1_path}, {backup_2_path}"
            , 'source_machine' : 'rocket'
            , 'verbose' : 'True'
            }
        config['COPY'] = \
            { 'sources' : f"{os.path.join(tmpdir, 'apache2/mods-enabled/dav_svn.conf')}"
            , 'additional_args' : "-v"
            }
        backup_1_path = os.path.join(tmpdir, "backup_1_path")
        backup_2_path = os.path.join(tmpdir, "backup_2_path")
        os.makedirs(backup_1_path)
        os.makedirs(backup_2_path)

        # Create files to be Rync'd
        apache_folder = os.path.join(tmpdir, "apache2")
        subdir = os.path.join(apache_folder, "mods-enabled")
        file = os.path.join(subdir, "dav_svn.conf")
        os.makedirs(apache_folder)
        os.makedirs(subdir)
        Path(file).touch()

        # Setup Schema
        schema = ConfigSchema(None)
        schema.add_section(DEFAULT_SCHEMA_SECTION)
        schema.add_section(COPY_SCHEMA_SECTION)

        # check that the rsync is successful (with options)
        sb = SvnBackup(config, schema)

        expected_file_bck1 = os.path.join(tmpdir, 'backup_1_path', 'dav_svn.conf')
        expected_file_bck2 = os.path.join(tmpdir, 'backup_2_path', 'dav_svn.conf')
        assert not os.path.exists(expected_file_bck1)
        assert not os.path.exists(expected_file_bck2)
        sb._run_copy()
        assert os.path.exists(expected_file_bck1)
        assert os.path.exists(expected_file_bck2)


class TestFullRunFromMain(object):

    def test_main_loads_and_runs_fine_when_given_config(self, tmpdir):
        config = configparser.ConfigParser()
        bpath1 = os.path.join(tmpdir, "path/1")
        bpath2 = os.path.join(tmpdir, "path/2")
        config['DEFAULT'] = \
            { 'backup_paths' :  f"{bpath1}, {bpath2}"
            , 'source_machine' : 'rocket'
            , 'verbose' : 'True'
            }
        copy_source = os.path.join(tmpdir, "copy/source")
        svn_conf_file = "dav_svn.conf"
        config['COPY'] = \
            { 'sources' : f'{copy_source}/{svn_conf_file}'
            }
        tar_source =  os.path.join(tmpdir, "tar/source")
        config['TAR'] = \
            { 'sources' : f"{tar_source}"
            , 'additional_args' : "--verbose -z -p -cf"
            , 'target_filename' : 'svnroot.tar.gz'
            , 'prefix_date' : 'False'
            }
        os.makedirs(bpath1)
        os.makedirs(bpath2)
        os.makedirs(copy_source)
        os.makedirs(tar_source)
        Path(os.path.join(copy_source, svn_conf_file)).touch()

        schema = ConfigSchema(None)
        schema.add_section(bckup.DEFAULT_SCHEMA_SECTION)
        schema.add_section(bckup.COPY_SCHEMA_SECTION)
        schema.add_section(bckup.TAR_SCHEMA_SECTION)

        svnbck_mod.main(config, schema)
        assert True is True


class TestSvnRsync(object):
    """Simple inherit of base class Backup"""

    def test_rsync_with_additional_args(self, tmpdir):

        # Setup config
        backup_1_path = os.path.join(tmpdir, "backup_1_path")
        backup_2_path = os.path.join(tmpdir, "backup_2_path")
        config = configparser.ConfigParser()
        config['DEFAULT'] = \
            { 'backup_paths' :  f"{backup_1_path}, {backup_2_path}"
            , 'source_machine' : 'rocket'
            , 'verbose' : 'True'
            }
        config['RSYNC'] = \
            { 'sources' : f"{os.path.join(tmpdir, 'svnroot')}"
            , 'additional_args' : "-a --delete-after"
            }
        backup_1_path = os.path.join(tmpdir, "backup_1_path")
        backup_2_path = os.path.join(tmpdir, "backup_2_path")
        os.makedirs(backup_1_path)
        os.makedirs(backup_2_path)

        # Create files to be Rync'd
        svnroot = os.path.join(tmpdir, "svnroot")
        subdir = os.path.join(svnroot, "some_dir")
        file1 = os.path.join(svnroot, "file_at_root_level")
        file2 = os.path.join(subdir, "file_in_subdir")
        os.makedirs(svnroot)
        os.makedirs(subdir)
        Path(file1).touch()
        Path(file2).touch()

        # File that will be removed because of --delete-after
        os.makedirs(os.path.join(backup_1_path, "svnroot"))
        file_that_already_existed = os.path.join(backup_1_path, "svnroot", "file_to_disappear")
        Path(file_that_already_existed).touch()
        assert os.path.exists(file_that_already_existed)

        # Setup Schema
        schema = ConfigSchema(None)
        schema.add_section(DEFAULT_SCHEMA_SECTION)
        schema.add_section(RSYNC_SCHEMA_SECTION)

        # check that the rsync is successful (with options)
        sb = SvnBackup(config, schema)

        expected1dir   = os.path.join(tmpdir, 'backup_1_path', 'svnroot', 'some_dir')
        expected1file1 = os.path.join(tmpdir, 'backup_1_path', 'svnroot', 'file_at_root_level')
        expected1file2 = os.path.join(tmpdir, 'backup_1_path', 'svnroot', 'some_dir/file_in_subdir')
        expected2dir   = os.path.join(tmpdir, 'backup_2_path', 'svnroot', 'some_dir')
        expected2file1 = os.path.join(tmpdir, 'backup_2_path', 'svnroot', 'file_at_root_level')
        expected2file2 = os.path.join(tmpdir, 'backup_2_path', 'svnroot', 'some_dir/file_in_subdir')
        assert not os.path.exists(expected1dir)
        assert not os.path.exists(expected1file1)
        assert not os.path.exists(expected1file2)
        assert not os.path.exists(expected2dir)
        assert not os.path.exists(expected2file1)
        assert not os.path.exists(expected2file2)
        assert os.path.exists(file_that_already_existed)
        sb._run_rsync()
        assert os.path.exists(expected1dir)
        assert os.path.exists(expected1file1)
        assert os.path.exists(expected1file2)
        assert os.path.exists(expected2dir)
        assert os.path.exists(expected2file1)
        assert os.path.exists(expected2file2)
        # file that does not exist in the source, is removed from the target
        assert not os.path.exists(file_that_already_existed)
