"""Tests for helper functions in Cg Compress CLI."""

import logging
from pathlib import Path
from typing import Iterator

from housekeeper.store.models import Version

from cg.apps.housekeeper.hk import HousekeeperAPI
from cg.cli.compress import helpers
from cg.cli.compress.helpers import set_memory_according_to_reads
from cg.constants.compression import CRUNCHY_MIN_GB_PER_PROCESS, MAX_READS_PER_GB


def test_set_memory_according_to_reads_when_no_reads(caplog, sample_id: str):
    """Test setting memory according to reads when no sample reads."""
    caplog.set_level(logging.DEBUG)

    # GIVEN a sample id and no reads supplied

    # WHEN setting memory according to reads
    memory: int = set_memory_according_to_reads(sample_id=sample_id, sample_reads=0)

    # THEN we should log
    assert f"No reads recorded for sample: {sample_id}" in caplog.text

    # THEN None should be returned
    assert memory is None


def test_set_memory_according_to_reads_when_few_reads(sample_id: str):
    """Test setting memory according to reads when few reads."""
    # GIVEN a sample id and reads

    # WHEN setting memory according to reads
    memory: int = set_memory_according_to_reads(sample_id=sample_id, sample_reads=1)

    # THEN memory should be set to the minimum
    assert memory == CRUNCHY_MIN_GB_PER_PROCESS


def test_set_memory_according_to_reads_when_many_reads(sample_id: str):
    """Test setting memory according to reads when many reads."""
    # GIVEN a sample id and reads

    # WHEN setting memory according to reads
    memory: int = set_memory_according_to_reads(
        sample_id=sample_id, sample_reads=MAX_READS_PER_GB**10
    )

    # THEN memory should be limited to what is available on the node
    assert memory == 180


def test_set_memory_according_to_reads(sample_id: str):
    """Test setting memory according to reads."""
    # GIVEN a sample id and reads

    # WHEN setting memory according to reads
    memory: int = set_memory_according_to_reads(
        sample_id=sample_id, sample_reads=MAX_READS_PER_GB * 100
    )

    # THEN memory should be adjusted
    assert memory == 100


def test_get_true_dir_no_symlinks(project_dir: Path):
    """Test to get a true dir when there are no symlinks."""
    # GIVEN a directory with some files but no symlinked files
    a_file: Path = Path(project_dir, "hello.txt")
    a_file.touch()
    assert a_file.exists()

    # WHEN fetching the true dir for the files in fixture dir
    true_dir = helpers.get_true_dir(a_file.parent)

    # THEN assert that the true_dir is None since there where no symbolic links in the project_dir
    assert true_dir is None


def test_get_true_dir_when_symlinks(project_dir: Path):
    """Test to get a true dir when there are symlinks to another directory.

    The function should return the path to another directory when there are symlinks in one.
    """
    # GIVEN a directory with a file with some content
    content = "hello world"
    a_file: Path = Path(project_dir, "hello.txt")
    a_file.write_text(content)
    assert a_file.exists()

    # GIVEN a subdirectory with a link to the above file
    new_dir: Path = Path(project_dir, "new_dir/")
    new_dir.mkdir()
    a_link: Path = Path(new_dir, "link_to_hello")
    a_link.symlink_to(a_file)
    assert a_link.read_text() == content
    assert a_link.parent == new_dir
    assert a_link.is_symlink() is True

    # WHEN fetching the true dir for the symlinked dir
    true_dir = helpers.get_true_dir(a_link.parent)

    # THEN assert that the true_dir the same as the parent of the destination of the symlink
    assert true_dir == project_dir


def test_get_versions_no_bundle(housekeeper_api: HousekeeperAPI):
    """Test to get latest versions of bundles when no bundles exists."""
    # GIVEN a empty housekeeper_api

    # WHEN fetching versions
    versions: Iterator[Version] = helpers.get_versions(housekeeper_api)

    # THEN assert no versions was returned
    assert sum(1 for version in versions) == 0


def test_get_versions_one_bundle(housekeeper_api: HousekeeperAPI, spring_bundle: dict):
    """Test to get latest versions of bundles when no bundles exists."""
    # GIVEN a populated housekeeper_api
    housekeeper_api.add_bundle(spring_bundle)

    # WHEN fetching versions
    versions = helpers.get_versions(housekeeper_api)

    # THEN assert no versions was returned
    assert sum(1 for version in versions) == 1


def test_correct_spring_paths(
    housekeeper_api: HousekeeperAPI,
    spring_bundle_symlink_problem: dict,
    symlinked_fastqs: dict,
):
    """Test for correct_spring_paths."""
    # GIVEN a populated housekeeper_api
    housekeeper_api.add_bundle(spring_bundle_symlink_problem)
    # GIVEN that the spring files exists in the wrong location
    versions: Iterator[Version] = helpers.get_versions(housekeeper_api)
    version: Version = next(versions)
    for file_path in version.files:
        assert not Path(file_path.full_path).exists()

    # WHEN updating the spring paths
    helpers.correct_spring_paths(housekeeper_api)

    # THEN assert that the spring paths has been moved
    for file_path in version.files:
        assert Path(file_path.full_path).exists()
