"""Tests for BALSAMIC analysis"""
from pathlib import Path

import pytest

from cg.constants.observations import ObservationsFileWildcards
from cg.constants.sequencing import Variants
from cg.constants.subject import Gender
from cg.exc import BalsamicStartError

from cg.meta.workflow.balsamic import BalsamicAnalysisAPI
from cg.models.cg_config import CGConfig


def test_get_verified_gender():
    """Tests gender extraction from a sample dictionary"""

    # GIVEN a sample object
    sample_obj = {
        "ACC0000A0": {"gender": "female"},
        "ACC0000A1": {"gender": "female"},
    }

    # WHEN extracting the gender
    retrieved_gender: Gender = BalsamicAnalysisAPI.get_verified_gender(sample_obj)

    # THEN gender must match the expected one
    assert retrieved_gender == "female"


def test_get_verified_gender_error():
    """Tests gender extraction from a sample dictionary when two different gender has been provided"""

    # GIVEN a sample object with different genders
    sample_obj = {
        "ACC0000A0": {"gender": "male"},
        "ACC0000A1": {"gender": "female"},
    }

    # WHEN extracting the gender
    with pytest.raises(BalsamicStartError):
        BalsamicAnalysisAPI.get_verified_gender(sample_obj)


def test_get_verified_gender_unknown(caplog):
    """Tests gender extraction from a sample dictionary when the gender is unknown"""

    # GIVEN a sample object with different genders
    sample_obj = {
        "ACC0000A0": {"gender": "unknown"},
        "ACC0000A1": {"gender": "unknown"},
    }

    # WHEN extracting the gender
    retrieved_gender: Gender = BalsamicAnalysisAPI.get_verified_gender(sample_obj)

    # THEN gender must match the expected one
    assert retrieved_gender == Gender.FEMALE
    assert f"The provided gender is unknown, setting {Gender.FEMALE} as the default" in caplog.text


def test_get_verified_pon():
    """Tests PON verification"""

    # GIVEN specific panel bed and PON files
    panel_bed = "/path/gmcksolid_4.1_hg19_design.bed"
    pon_cnn = "/path/PON/gmcksolid_4.1_hg19_design_CNVkit_PON_reference_v2.cnn"
    invalid_pon_cnn = "/path/PON/gmssolid_15.2_hg19_design_CNVkit_PON_reference_v2.cnn"

    # WHEN validating the PON
    validated_pon: str = BalsamicAnalysisAPI.get_verified_pon(None, panel_bed, pon_cnn)

    # THEN the PON verification should be performed successfully
    assert pon_cnn == validated_pon
    with pytest.raises(BalsamicStartError):
        BalsamicAnalysisAPI.get_verified_pon(None, panel_bed, invalid_pon_cnn)


def test_get_latest_file_by_pattern(
    cg_context: CGConfig, observations_dir: Path, observations_somatic_snv_file_path: Path
):
    """Test latest observations extraction."""

    # GIVEN a Loqusdb temporary directory and a cancer SNV file wildcard
    balsamic_analysis_api: BalsamicAnalysisAPI = BalsamicAnalysisAPI(cg_context)

    # WHEN getting the latest observations file
    observation: str = balsamic_analysis_api.get_latest_file_by_pattern(
        directory=observations_dir, pattern=ObservationsFileWildcards.CANCER_SOMATIC_SNV
    )

    # THEN the extracted observation should match the latest file
    assert observation == observations_somatic_snv_file_path.as_posix()


def test_get_parsed_observation_file_paths_no_args(
    cg_context: CGConfig,
    observations_dir: Path,
    observations_clinical_sv_file_path: Path,
    observations_somatic_snv_file_path: Path,
    outdated_observations_somatic_snv_file_path: Path,
):
    """Test verified observations extraction with no arguments."""

    # GIVEN a Loqusdb temporary directory
    balsamic_analysis_api: BalsamicAnalysisAPI = BalsamicAnalysisAPI(cg_context)
    balsamic_analysis_api.loqusdb_path = observations_dir

    # WHEN getting the latest observations arguments dictionary
    args: dict = balsamic_analysis_api.get_parsed_observation_file_paths(None)

    # THEN only the created observations files should be returned
    assert args[ObservationsFileWildcards.CLINICAL_SNV] is None
    assert (
        args[ObservationsFileWildcards.CLINICAL_SV] == observations_clinical_sv_file_path.as_posix()
    )
    assert args[ObservationsFileWildcards.CANCER_GERMLINE_SNV] is None
    assert args[ObservationsFileWildcards.CANCER_GERMLINE_SV] is None
    assert (
        args[ObservationsFileWildcards.CANCER_SOMATIC_SNV]
        == observations_somatic_snv_file_path.as_posix()
    )
    assert (
        outdated_observations_somatic_snv_file_path.as_posix()
        not in args[ObservationsFileWildcards.CANCER_SOMATIC_SNV]
    )
    assert args[ObservationsFileWildcards.CANCER_SOMATIC_SV] is None


def test_get_parsed_observation_file_paths_overwrite_input(
    cg_context: CGConfig,
    observations_dir: Path,
    observations_clinical_snv_file_path: Path,
    custom_observations_clinical_snv_file_path: Path,
):
    """Test verified observations extraction when providing a non default observation file."""

    # GIVEN a Loqusdb temporary directory and a custom Loqusdb file
    balsamic_analysis_api: BalsamicAnalysisAPI = BalsamicAnalysisAPI(cg_context)
    balsamic_analysis_api.loqusdb_path = observations_dir

    # WHEN getting the latest observations dictionary
    args: dict = balsamic_analysis_api.get_parsed_observation_file_paths(
        [custom_observations_clinical_snv_file_path.as_posix()]
    )

    # THEN the default file should be overwritten by the custom file
    assert (
        observations_clinical_snv_file_path.as_posix()
        not in args[ObservationsFileWildcards.CLINICAL_SNV]
    )
    assert (
        args[ObservationsFileWildcards.CLINICAL_SNV]
        == custom_observations_clinical_snv_file_path.as_posix()
    )


def test_get_swegen_verified_path(
    cg_context: CGConfig, swegen_dir: Path, swegen_snv_reference: Path
):
    """Test verified SweGen path return."""

    # GIVEN A SNV variants pattern and a BALSAMIC analysis API
    balsamic_analysis_api: BalsamicAnalysisAPI = BalsamicAnalysisAPI(cg_context)
    balsamic_analysis_api.swegen_path = swegen_dir

    # WHEN obtaining the latest file by pattern
    swegen_file: str = balsamic_analysis_api.get_swegen_verified_path(Variants.SNV)

    # THEN the returned file should match the SweGen SNV reference
    assert swegen_file == swegen_snv_reference.as_posix()
