from pathlib import Path

from tests.test_integration import get_files_in_dir
from utils.db_handling import DbAccessor
from utils.db_handling.db_access import DbObjBuilder
from utils.vars import PROPHANE_DIR
import os
import pytest
import shutil


def copy(src, dst):
    if os.path.isdir(src):
        shutil.copytree(src, os.path.join(dst, os.path.basename(src)))
    else:
        shutil.copy(src, dst)


def setup_test_dbs(source_db_dir, target_dir):
    from tests import setup_test
    source_base_dir_name = os.path.basename(os.path.normpath(source_db_dir))
    copy(source_db_dir, str(target_dir))
    new_db_dir = str(target_dir.join(source_base_dir_name))
    setup_test.set_db_config_paths(
        db_base_dir=new_db_dir
    )
    return new_db_dir


@pytest.fixture()
def prophane_test_dbs(tmpdir):
    source_db_dir = os.path.join(os.path.dirname(__file__), 'test_dbs')
    target_dir = tmpdir
    source_base_dir_name = os.path.basename(os.path.normpath(source_db_dir))
    copy(source_db_dir, str(target_dir))
    new_db_dir = str(target_dir.join(source_base_dir_name))
    return new_db_dir


@pytest.fixture()
def test_dbs_only_dl_files(tmpdir):
    # patch date based versions to fit test-dbs
    date = "2018-08-08"
    env_key = 'MOCKED_DATE'
    env = os.environ
    stored_var = env.get(env_key)
    env[env_key] = date

    # setup dbs
    tgt_db_dir = os.path.join(tmpdir, 'test_dbs')
    source_db_dir = os.path.join(PROPHANE_DIR, 'tests', 'test_dbs')
    dbacc = DbAccessor(source_db_dir)

    for db_obj_src in dbacc.get_db_objects():
        db_type = db_obj_src.get_type()
        ver = db_obj_src.get_version()
        db_obj_tgt = DbObjBuilder(db_type, ver, tgt_db_dir, check_required_file_presence=False).create()
        for key, tgt_f_rel_to_db in db_obj_tgt._config["files"].items():
            src_f = db_obj_src.join_with_db_path(db_obj_src._config["files"][key])
            tgt_f_o = Path(db_obj_tgt.join_with_db_path(tgt_f_rel_to_db))
            tgt_f_o.parent.mkdir(parents=True, exist_ok=True)
            tgt_f = str(tgt_f_o)
            if Path(src_f).is_dir():
                tgt_f = str(tgt_f_o.parent)
            copy(src_f, tgt_f)
            if os.path.exists(src_f+".md5"):
                copy(src_f+".md5", tgt_f+".md5")
    yield tgt_db_dir
    # restore environment
    if stored_var:
        env[env_key] = stored_var
    else:
        del env[env_key]


@pytest.fixture()
def test_dbs_preprocessed(tmpdir):
    tgt_db_dir = os.path.join(tmpdir, 'test_dbs')
    source_db_dir = os.path.join(PROPHANE_DIR, 'tests', 'resources', 'test_db_preprocessing', 'expected-dbs')
    os.mkdir(tgt_db_dir)
    copy(source_db_dir, tmpdir)
    os.rename(tmpdir.join(os.path.basename(source_db_dir)), tgt_db_dir)
    return tgt_db_dir


@pytest.fixture()
def prophane_test_dbs_before_map_gz(tmpdir):
    source_db_dir = os.path.join(os.path.dirname(__file__), 'test_dbs_before_map_gz')
    db_dir = setup_test_dbs(source_db_dir, tmpdir)
    return db_dir


@pytest.fixture()
def prophane_input():
    def _setup(test_dir, tmpdir, db_dir=''):
        """
        Copy files from test_dir/job_dir to tmpdir/job_dir
        and adjust preliminary paths in config file copied from test_dir/job_dir/
        :param test_dir: folder containing 'job_dir'
        :param tmpdir: 'test_dir/job_dir' is copied here
        :param db_dir: database base directory; needed for updating database paths in input config; if not specified,
            'tmpddir/test_dbs' is set as database base path
        :return:
            path of config file
            job directory
        """
        db_dir = db_dir if db_dir != '' else os.path.join(tmpdir, 'test_dbs')
        assert os.path.isdir(db_dir), f"Missing directory: {db_dir}"
        from tests import setup_test
        job_dir = os.path.join(tmpdir, 'job_dir')
        copy(os.path.join(os.path.dirname(__file__), test_dir, "job_dir"), tmpdir)
        yamls = setup_test.set_prophane_config_paths(
            db_base_dir=db_dir,
            prophane_base_dir=PROPHANE_DIR,
            job_base_dir=job_dir,
            general_config_path=os.path.join(job_dir, "general_config.yaml")
        )
        job_yamls = [yaml for yaml in yamls if 'input/' in os.path.relpath(yaml, job_dir)]
        assert len(job_yamls) == 1, 'got "{}" prophane job config yamls. Expected exactly 1.'\
            .format(len(yamls))
        return job_yamls[0], job_dir
    return _setup


@pytest.fixture()
def f_proteomic_search_result():
    def _setup(test_dir, tmpdir):
        """
        Copy files from test_dir/job_dir to tmpdir/job_dir
        :param test_dir: folder containing 'job_dir'
        :param tmpdir: 'test_dir/job_dir' is copied here
        :return:
            path of proteomic_search_result
            job directory
        """
        from tests.test_integration import copy
        job_dir = os.path.join(tmpdir, 'job_dir')
        test_data = os.path.join(os.path.dirname(__file__), test_dir, "job_dir")
        copy(test_data, tmpdir)
        lst_files = get_files_in_dir(job_dir)
        assert len(lst_files) == 1, "expected a single file in:\n\t'{job_dir}'\n\tfound: {n}" \
            .format(job_dir=job_dir, n=len(lst_files))
        proteomic_search_result = os.path.abspath(lst_files[0])
        return proteomic_search_result, job_dir
    return _setup


@pytest.fixture(scope='session')
def conda_dir(tmpdir_factory):
    path = tmpdir_factory.mktemp('conda_envs')
    return path
