# =======================
# Python internal package
# =======================
# D
import dataclasses

# S
import subprocess

# ================
# External package
# ================
# P
import pytest


@dataclasses.dataclass
class Argument:
    """A dataclass to simulate parsed argument."""

    input: str | list[str] = "tests/data/ligand.pdb"
    output: str = "tests/data/interaction.csv"
    selection: list[str] | None = dataclasses.field(default_factory=list)
    parameter: str | None = None
    pharmacophore: tuple[str, str] | None = (
        "tests/data/pharmacophore_1.csv",
        "tests/data/pharmacophore_2.csv",
    )
    feature_file: str | None = None
    visualization: str | None = "tests/data/visualization.mvsj"
    add_hydrogen: int = 0


@pytest.mark.parametrize(
    "argument, error_code",
    [
        ({}, 0),
        ({"input": "tests/data/ligand.mol2"}, 0),
        ({"input": "tests/data/ligand.sdf"}, 0),
        ({"input": "NA"}, 1),
        ({"input": ["NA", "NA"]}, 1),
        ({"input": ["tests/data/ligand.pdb", "NA"]}, 1),
        ({"input": ["tests/data/ligand.pdb"] * 2}, 0),
        ({"input": ["tests/data/ligand.pdb"] * 3}, 1),
        ({"output": "NA"}, 1),
        ({"output": "NA/interaction.csv"}, 1),
        ({"selection": [""]}, 0),
        ({"selection": [""] * 2}, 0),
        ({"selection": [""] * 3}, 1),
        ({"pharmacophore": ["tests/data/pharmacophore_1.csv"]}, 1),
        ({"pharmacophore": ["tests/data/pharmacophore_1.csv"] * 2}, 1),
        ({"pharmacophore": ["NA"] * 2}, 1),
        ({"pharmacophore": ["NA/pharmacophore_1.csv"] * 2}, 1),
    ],
)
def test_command_line_interface(
    argument: dict[str, str | int | list[str]],
    error_code: int,
) -> None:
    """
    Test the command-line interface (CLI) behavior for various argument
    combinations.

    Parameters
    ----------
    argument : `dict[str, str | int | list[str]]`
        A dictionary representing the CLI arguments to be passed. Keys
        correspond to argument names and values represent their associated
        parameters.

    error_code : `int`
        The expected return code of the CLI process. A value of `0` indicates
        successful execution, while `1` indicates an error condition.
    """
    command: list[str] = ["python", "-m", "src.strange"]

    for key, value in dataclasses.asdict(Argument(**argument)).items():
        if value is None or value == []:
            continue

        if not isinstance(value, (list, tuple)):
            value = [str(value)]
        command += [f"--{key}"] + list(value)

    result: subprocess.CompletedProcess[str] = subprocess.run(
        command, capture_output=True, text=True
    )

    assert result.returncode == error_code
