import os
import shutil
from datetime import datetime
from pathlib import Path

import pytest

from entropylab.logger import logger
from entropylab.pipeline.results_backend.sqlalchemy.db_initializer import (
    _ENTROPY_DIRNAME,
    _DB_FILENAME,
)

"""conftest.py is a standard pytest configuration file (see here:
https://docs.pytest.org/en/6.2.x/fixture.html).

This conftest.py file contains pytest test fixtures that generate project-related test
data and, on test tear-down, remove the data from disk.
"""


# Test fixtures


@pytest.fixture()
def project_dir_path(request) -> str:
    """Generate a unique path to a (non-existent) project directory
    The directory will be removed recursively on tear down"""
    dir_path = _build_project_dir_path_for_test(request)
    yield dir_path
    _delete_if_exists(dir_path)


@pytest.fixture()
def db_file_path(request) -> str:
    """Generate a unique path to a (non-existent) sqlite db file
    The file will be removed on tear down"""
    dir_path = _build_project_dir_path_for_test(request)
    file_path = dir_path + ".db"
    yield file_path
    _delete_if_exists(file_path)
    _delete_if_exists(dir_path)


@pytest.fixture()
def tinydb_file_path(request) -> str:
    """Generate a unique path to a (non-existent) tinydb json file
    The file will be removed on tear down"""
    dir_path = _build_project_dir_path_for_test(request)
    file_path = os.path.join(dir_path + "/" + "tiny_db.json")
    yield file_path
    _delete_if_exists(dir_path)


@pytest.fixture()
def initialized_project_dir_path(request, project_dir_path) -> str:
    """Create an initialized project and return the path to its directory
    The directory will be removed recursively on tear down"""
    entropy_dir = os.path.join(project_dir_path, _ENTROPY_DIRNAME)
    os.makedirs(entropy_dir)
    # if used in a parametrized test, consider the parameter as a db_template
    # and use a copy of it as the db:
    if hasattr(request, "param") and request.param is not None:
        # param input from test annotation is the db_template file name:
        db_template = os.path.join("./db_templates", str(request.param))
        db_file = os.path.join(entropy_dir, _DB_FILENAME)
        _copy_template(db_template, db_file, request)
    return project_dir_path


# Internal implementations


def _build_project_dir_path_for_test(request):
    project_dir_path = (
        f"tests_cache/{request.node.name}_{datetime.now():%Y-%m-%d-%H-%M-%S}"
    )
    if os.path.isdir(project_dir_path):
        logger.info(f"Test cleanup. Deleting directory '{project_dir_path}'")
        shutil.rmtree(project_dir_path)
    Path(project_dir_path).mkdir(parents=True, exist_ok=True)
    return project_dir_path


def _delete_if_exists(path: str):
    if os.path.isdir(path):
        logger.debug(f"Test cleanup. Deleting directory '{path}'")
        shutil.rmtree(path)
    elif os.path.isfile(path):
        logger.debug(f"Test cleanup. Deleting file '{path}'")
        os.remove(path)


def _copy_template(src, dst, request):
    """Copy the source template file (path relative to test file) to the destination"""
    if src is not None and src != "":
        abs_src = os.path.join(request.fspath.dirname, src)
        logger.debug(f"Copied db template from '{abs_src}' to '{dst}'")
        shutil.copyfile(abs_src, dst)

import os
import shutil
from datetime import datetime
from pathlib import Path

import pytest

from entropylab.logger import logger
from entropylab.pipeline.results_backend.sqlalchemy.db_initializer import (
    _ENTROPY_DIRNAME,
    _DB_FILENAME,
)

"""conftest.py is a standard pytest configuration file (see here:
https://docs.pytest.org/en/6.2.x/fixture.html).

This conftest.py file contains pytest test fixtures that generate project-related test
data and, on test tear-down, remove the data from disk.
"""


# Test fixtures


@pytest.fixture()
def project_dir_path(request) -> str:
    """Generate a unique path to a (non-existent) project directory
    The directory will be removed recursively on tear down"""
    dir_path = _build_project_dir_path_for_test(request)
    yield dir_path
    _delete_if_exists(dir_path)


@pytest.fixture()
def db_file_path(request) -> str:
    """Generate a unique path to a (non-existent) sqlite db file
    The file will be removed on tear down"""
    dir_path = _build_project_dir_path_for_test(request)
    file_path = dir_path + ".db"
    yield file_path
    _delete_if_exists(file_path)
    _delete_if_exists(dir_path)


@pytest.fixture()
def tinydb_file_path(request) -> str:
    """Generate a unique path to a (non-existent) tinydb json file
    The file will be removed on tear down"""
    dir_path = _build_project_dir_path_for_test(request)
    file_path = os.path.join(dir_path + "/" + "tiny_db.json")
    yield file_path
    _delete_if_exists(dir_path)


@pytest.fixture()
def initialized_project_dir_path(request, project_dir_path) -> str:
    """Create an initialized project and return the path to its directory
    The directory will be removed recursively on tear down"""
    entropy_dir = os.path.join(project_dir_path, _ENTROPY_DIRNAME)
    os.makedirs(entropy_dir)
    # if used in a parametrized test, consider the parameter as a db_template
    # and use a copy of it as the db:
    if hasattr(request, "param") and request.param is not None:
        # param input from test annotation is the db_template file name:
        db_template = os.path.join("./db_templates", str(request.param))
        db_file = os.path.join(entropy_dir, _DB_FILENAME)
        _copy_template(db_template, db_file, request)
    return project_dir_path


# Internal implementations


def _build_project_dir_path_for_test(request):
    project_dir_path = (
        f"tests_cache/{request.node.name}_{datetime.now():%Y-%m-%d-%H-%M-%S}"
    )
    if os.path.isdir(project_dir_path):
        logger.info(f"Test cleanup. Deleting directory '{project_dir_path}'")
        shutil.rmtree(project_dir_path)
    Path(project_dir_path).mkdir(parents=True, exist_ok=True)
    return project_dir_path


def _delete_if_exists(path: str):
    if os.path.isdir(path):
        logger.debug(f"Test cleanup. Deleting directory '{path}'")
        shutil.rmtree(path)
    elif os.path.isfile(path):
        logger.debug(f"Test cleanup. Deleting file '{path}'")
        os.remove(path)


def _copy_template(src, dst, request):
    """Copy the source template file (path relative to test file) to the destination"""
    if src is not None and src != "":
        abs_src = os.path.join(request.fspath.dirname, src)
        logger.debug(f"Copied db template from '{abs_src}' to '{dst}'")
        shutil.copyfile(abs_src, dst)

conftest.py is a standard pytest configuration file (see here: https://docs.pytest.org/en/6.2.x/fixture.html).  This conftest.py file contains pytest test fixtures that generate project-related test data and, on test tear-down, remove the data from disk. # Test fixtures Generate a unique path to a (non-existent) project directory     The directory will be removed recursively on tear down Generate a unique path to a (non-existent) sqlite db file     The file will be removed on tear down Generate a unique path to a (non-existent) tinydb json file     The file will be removed on tear down Create an initialized project and return the path to its directory     The directory will be removed recursively on tear down # if used in a parametrized test, consider the parameter as a db_template # and use a copy of it as the db: # param input from test annotation is the db_template file name: # Internal implementations Copy the source template file (path relative to test file) to the destination