# Path: pyani/fastani.py
# class PyaniFastANIException(PyaniException):
# class ComparisonResult(NamedTuple):
# def get_version(fastani_exe: Path = pyani_config.FASTANI_DEFAULT) -> str:
# def generate_fastani_jobs(
#     filenames: List[Path],
#     outdir: Path = Path("."),
#     fastani_exe: Path = pyani_config.FASTANI_DEFAULT,
#     fragLen: int = 3000,
#     kmerSize: int = 16,
#     minFraction: float = 0.2,
#     jobprefix: str = "fastANI",
# ):  # should this have a hint for return type?
# def generate_fastani_commands(
#     filenames: List[Path],
#     outdir: Path = Path("."),
#     fastani_exe: Path = pyani_config.FASTANI_DEFAULT,
#     fragLen: int = 3000,
#     kmerSize: int = 16,
#     minFraction: float = 0.2,
# ) -> List[str]:
# def construct_fastani_cmdline(
#     query: Path,
#     ref: Path,
#     outdir: Path = Path("."),
#     fastani_exe: Path = pyani_config.FASTANI_DEFAULT,
#     fragLen: int = 3000,
#     kmerSize: int = 16,
#     minFraction: float = 0.2,
# ) -> str:
# def parse_fastani_file(filename: Path) -> ComparisonResult:
# def process_files(outdir: Path, org_lengths: Dict) -> ANIResults:
# 
# Path: pyani/pyani_files.py
# class PyaniFilesException(PyaniException):
# def get_fasta_files(dirname: Path = Path(".")) -> List[Path]:
# def get_fasta_paths(
#     dirname: Path = Path("."), extlist: Optional[List] = None
# ) -> List[Path]:
# def get_fasta_and_hash_paths(dirname: Path = Path(".")) -> List[Tuple[Path, Path]]:
# def get_input_files(dirname: Path, *ext) -> List[Path]:
# def get_sequence_lengths(fastafilenames: Iterable[Path]) -> Dict[str, int]:
# def read_hash_string(filename: Path) -> Tuple[str, str]:
# def read_fasta_description(filename: Path) -> str:
# def load_classes_labels(path: Path) -> Dict[str, str]:
# def collect_existing_output(dirpath: Path, program: str, args: Namespace) -> List[Path]:
# 
# Path: pyani/pyani_tools.py
# class MatrixData(NamedTuple):
# class Dependencies(NamedTuple):
# class ANIResults:
# class BLASTfunctions(NamedTuple):
# class BLASTexes(NamedTuple):
# class BLASTcmds:
#     def __init__(self, labels: List[str], mode: str) -> None:
#     def add_tot_length(
#         self, qname: str, sname: str, value: float, sym: bool = True
#     ) -> None:
#     def add_sim_errors(
#         self, qname: str, sname: str, value: float, sym: bool = True
#     ) -> None:
#     def add_pid(self, qname: str, sname: str, value: float, sym: bool = True) -> None:
#     def add_coverage(
#         self, qname: str, sname: str, qcover: float, scover: Optional[float] = None
#     ) -> None:
#     def hadamard(self) -> float:
#     def data(self) -> Iterator[Tuple[Any, str]]:
#     def __init__(
#         self, funcs: BLASTfunctions, exes: BLASTexes, prefix: str, outdir: Path
#     ) -> None:
#     def build_db_cmd(self, fname: Path) -> str:
#     def get_db_name(self, fname: Path) -> str:
#     def build_blast_cmd(self, fname: Path, dbname: Path):
# def get_labels(filename: Path, logger: Optional[Logger] = None) -> Dict:
# def get_genome_length(filename: Path) -> int:
# def label_results_matrix(matrix: pd.DataFrame, labels: Dict) -> pd.DataFrame:
# def has_dependencies() -> Dependencies:
# def termcolor(
#     logstr: str, color: Optional[str] = None, bold: Optional[bool] = False
# ) -> str:


import os
import pandas as pd
import pytest
import unittest
from pathlib import Path
from typing import List, NamedTuple, Tuple
from pandas.util.testing import assert_frame_equal
from pyani import fastani, pyani_files, pyani_tools

# Test fastANI command generation
def test_fastani_single(tmp_path, path_file_two):  # works
    """Generate single fastANI command line."""
    fastcmd = fastani.construct_fastani_cmdline(
        path_file_two[0], path_file_two[1], outdir=tmp_path
    )
    dir_fastani = tmp_path / "fastani_output"
    expected = (
        f"fastANI -q {path_file_two[0]} -r {path_file_two[1]} "
        f"-o {dir_fastani / str(path_file_two[0].stem + '_vs_' + path_file_two[1].stem + '.fastani')} "
        f"--fragLen 3000 -k 16 --minFraction 0.2"
    )
    assert fastcmd == expected


def test_fastani_multiple(fastani_cmds_four):
    """Generate multiple abstract fastANI command-liens.

    Tests that all the input files are correctly-paired.
    """
    cmds = fastani.generate_fastani_commands(fastani_cmds_four.infiles)
    print(f"\n{cmds}")
    print((fastani_cmds_four.fastcmds))
    assert cmds == (fastani_cmds_four.fastcmds)


def test_fastani_job_generation(fastani_cmds_four):  # works
    """Generate job names"""


# Path: pyani/fastani.py
# class PyaniFastANIException(PyaniException):
# class ComparisonResult(NamedTuple):
# def get_version(fastani_exe: Path = pyani_config.FASTANI_DEFAULT) -> str:
# def generate_fastani_jobs(
#     filenames: List[Path],
#     outdir: Path = Path("."),
#     fastani_exe: Path = pyani_config.FASTANI_DEFAULT,
#     fragLen: int = 3000,
#     kmerSize: int = 16,
#     minFraction: float = 0.2,
#     jobprefix: str = "fastANI",
# ):  # should this have a hint for return type?
# def generate_fastani_commands(
#     filenames: List[Path],
#     outdir: Path = Path("."),
#     fastani_exe: Path = pyani_config.FASTANI_DEFAULT,
#     fragLen: int = 3000,
#     kmerSize: int = 16,
#     minFraction: float = 0.2,
# ) -> List[str]:
# def construct_fastani_cmdline(
#     query: Path,
#     ref: Path,
#     outdir: Path = Path("."),
#     fastani_exe: Path = pyani_config.FASTANI_DEFAULT,
#     fragLen: int = 3000,
#     kmerSize: int = 16,
#     minFraction: float = 0.2,
# ) -> str:
# def parse_fastani_file(filename: Path) -> ComparisonResult:
# def process_files(outdir: Path, org_lengths: Dict) -> ANIResults:
# 
# Path: pyani/pyani_files.py
# class PyaniFilesException(PyaniException):
# def get_fasta_files(dirname: Path = Path(".")) -> List[Path]:
# def get_fasta_paths(
#     dirname: Path = Path("."), extlist: Optional[List] = None
# ) -> List[Path]:
# def get_fasta_and_hash_paths(dirname: Path = Path(".")) -> List[Tuple[Path, Path]]:
# def get_input_files(dirname: Path, *ext) -> List[Path]:
# def get_sequence_lengths(fastafilenames: Iterable[Path]) -> Dict[str, int]:
# def read_hash_string(filename: Path) -> Tuple[str, str]:
# def read_fasta_description(filename: Path) -> str:
# def load_classes_labels(path: Path) -> Dict[str, str]:
# def collect_existing_output(dirpath: Path, program: str, args: Namespace) -> List[Path]:
# 
# Path: pyani/pyani_tools.py
# class MatrixData(NamedTuple):
# class Dependencies(NamedTuple):
# class ANIResults:
# class BLASTfunctions(NamedTuple):
# class BLASTexes(NamedTuple):
# class BLASTcmds:
#     def __init__(self, labels: List[str], mode: str) -> None:
#     def add_tot_length(
#         self, qname: str, sname: str, value: float, sym: bool = True
#     ) -> None:
#     def add_sim_errors(
#         self, qname: str, sname: str, value: float, sym: bool = True
#     ) -> None:
#     def add_pid(self, qname: str, sname: str, value: float, sym: bool = True) -> None:
#     def add_coverage(
#         self, qname: str, sname: str, qcover: float, scover: Optional[float] = None
#     ) -> None:
#     def hadamard(self) -> float:
#     def data(self) -> Iterator[Tuple[Any, str]]:
#     def __init__(
#         self, funcs: BLASTfunctions, exes: BLASTexes, prefix: str, outdir: Path
#     ) -> None:
#     def build_db_cmd(self, fname: Path) -> str:
#     def get_db_name(self, fname: Path) -> str:
#     def build_blast_cmd(self, fname: Path, dbname: Path):
# def get_labels(filename: Path, logger: Optional[Logger] = None) -> Dict:
# def get_genome_length(filename: Path) -> int:
# def label_results_matrix(matrix: pd.DataFrame, labels: Dict) -> pd.DataFrame:
# def has_dependencies() -> Dependencies:
# def termcolor(
#     logstr: str, color: Optional[str] = None, bold: Optional[bool] = False
# ) -> str:


# Path: tests/test_fastani.py
import os
import pandas as pd
import pytest
import unittest
from pathlib import Path
from typing import List, NamedTuple, Tuple
from pandas.util.testing import assert_frame_equal
from pyani import fastani, pyani_files, pyani_tools


# Test fastANI command generation
def test_fastani_single(tmp_path, path_file_two):  # works
    """Generate single fastANI command line."""
    fastcmd = fastani.construct_fastani_cmdline(
        path_file_two[0], path_file_two[1], outdir=tmp_path
    )
    dir_fastani = tmp_path / "fastani_output"
    expected = (
        f"fastANI -q {path_file_two[0]} -r {path_file_two[1]} "
        f"-o {dir_fastani / str(path_file_two[0].stem + '_vs_' + path_file_two[1].stem + '.fastani')} "
        f"--fragLen 3000 -k 16 --minFraction 0.2"
    )
    assert fastcmd == expected


def test_fastani_multiple(fastani_cmds_four):
    """Generate multiple abstract fastANI command-liens.

    Tests that all the input files are correctly-paired.
    """
    cmds = fastani.generate_fastani_commands(fastani_cmds_four.infiles)
    print(f"\n{cmds}")
    print((fastani_cmds_four.fastcmds))
    assert cmds == (fastani_cmds_four.fastcmds)


def test_fastani_job_generation(fastani_cmds_four):  # works
    """Generate job names"""


    joblist = fastani.generate_fastani_jobs(fastani_cmds_four.infiles, jobprefix="test")