# pylint: disable=missing-module-docstring

import io
import os
import subprocess
import typing
import unittest.mock

import pandas
import pandas.util.testing
import pytest

import freesurfer_volume_reader
import freesurfer_volume_reader.__main__

# pylint: disable=wrong-import-order; false positive
from conftest import SUBJECTS_DIR, assert_volume_frames_equal


def assert_main_volume_frame_equals(
    capsys,
    argv: list,
    expected_frame: pandas.DataFrame,
    subjects_dir: typing.Optional[str] = None,
):
    if subjects_dir:
        os.environ["SUBJECTS_DIR"] = subjects_dir
    elif "SUBJECTS_DIR" in os.environ:
        del os.environ["SUBJECTS_DIR"]
    with unittest.mock.patch("sys.argv", [""] + argv):
        assert freesurfer_volume_reader.__main__.main() == 0
    out, _ = capsys.readouterr()
    resulted_frame = pandas.read_csv(io.StringIO(out)).drop(columns=["source_path"])
    if "correction" in resulted_frame:
        resulted_frame["correction"] = resulted_frame["correction"].astype("object")
    assert_volume_frames_equal(
        left=expected_frame,
        # pandas.DataFrame.drop(columns=[...], ...) >= pandas0.21.0
        right=resulted_frame,
    )


@pytest.mark.parametrize(
    ("args", "root_dir_paths", "expected_csv_path"),
    [
        (
            [],
            [os.path.join(SUBJECTS_DIR, "alice")],
            os.path.join(SUBJECTS_DIR, "alice", "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            [],
            [os.path.join(SUBJECTS_DIR, "bert")],
            os.path.join(SUBJECTS_DIR, "bert", "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            [],
            [os.path.join(SUBJECTS_DIR, "alice"), os.path.join(SUBJECTS_DIR, "bert")],
            os.path.join(SUBJECTS_DIR, "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            [],
            [SUBJECTS_DIR],
            os.path.join(SUBJECTS_DIR, "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "freesurfer-hipposf"],
            [os.path.join(SUBJECTS_DIR, "alice")],
            os.path.join(SUBJECTS_DIR, "alice", "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "freesurfer-hipposf"],
            [SUBJECTS_DIR],
            os.path.join(SUBJECTS_DIR, "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs"],
            [os.path.join(SUBJECTS_DIR, "alice")],
            os.path.join(SUBJECTS_DIR, "alice", "ashs-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs"],
            [os.path.join(SUBJECTS_DIR, "bert")],
            os.path.join(SUBJECTS_DIR, "bert", "ashs-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs"],
            [os.path.join(SUBJECTS_DIR, "alice"), os.path.join(SUBJECTS_DIR, "bert")],
            os.path.join(SUBJECTS_DIR, "ashs-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs"],
            [SUBJECTS_DIR],
            os.path.join(SUBJECTS_DIR, "ashs-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs", "freesurfer-hipposf"],
            [os.path.join(SUBJECTS_DIR, "alice")],
            os.path.join(SUBJECTS_DIR, "alice", "all-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "freesurfer-hipposf", "ashs"],
            [os.path.join(SUBJECTS_DIR, "alice")],
            os.path.join(SUBJECTS_DIR, "alice", "all-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs", "freesurfer-hipposf"],
            [os.path.join(SUBJECTS_DIR, "alice"), os.path.join(SUBJECTS_DIR, "bert")],
            os.path.join(SUBJECTS_DIR, "all-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs", "freesurfer-hipposf"],
            [SUBJECTS_DIR],
            os.path.join(SUBJECTS_DIR, "all-hippocampal-volumes.csv"),
        ),
    ],
)
def test_main_root_dir_param(capsys, args, root_dir_paths: list, expected_csv_path):
    assert_main_volume_frame_equals(
        argv=args + ["--"] + root_dir_paths,
        expected_frame=pandas.read_csv(expected_csv_path),
        capsys=capsys,
    )


@pytest.mark.parametrize(
    ("args", "root_dir_path", "expected_csv_path"),
    [
        (
            [],
            SUBJECTS_DIR,
            os.path.join(SUBJECTS_DIR, "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            [],
            os.path.join(SUBJECTS_DIR, "bert"),
            os.path.join(SUBJECTS_DIR, "bert", "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "freesurfer-hipposf"],
            SUBJECTS_DIR,
            os.path.join(SUBJECTS_DIR, "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "freesurfer-hipposf"],
            os.path.join(SUBJECTS_DIR, "bert"),
            os.path.join(SUBJECTS_DIR, "bert", "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "freesurfer-hipposf"],
            os.path.join(SUBJECTS_DIR, "bert", "mri"),
            os.path.join(SUBJECTS_DIR, "bert", "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs"],
            SUBJECTS_DIR,
            os.path.join(SUBJECTS_DIR, "ashs-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs"],
            os.path.join(SUBJECTS_DIR, "bert"),
            os.path.join(SUBJECTS_DIR, "bert", "ashs-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs"],
            os.path.join(SUBJECTS_DIR, "bert", "final"),
            os.path.join(SUBJECTS_DIR, "bert", "ashs-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs"],
            os.path.join(SUBJECTS_DIR, "alice"),
            os.path.join(SUBJECTS_DIR, "alice", "ashs-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs", "freesurfer-hipposf"],
            os.path.join(SUBJECTS_DIR, "alice"),
            os.path.join(SUBJECTS_DIR, "alice", "all-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "freesurfer-hipposf", "ashs"],
            os.path.join(SUBJECTS_DIR, "alice"),
            os.path.join(SUBJECTS_DIR, "alice", "all-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "freesurfer-hipposf", "ashs"],
            SUBJECTS_DIR,
            os.path.join(SUBJECTS_DIR, "all-hippocampal-volumes.csv"),
        ),
    ],
)
def test_main_root_dir_env(capsys, args, root_dir_path, expected_csv_path):
    assert_main_volume_frame_equals(
        argv=args,
        subjects_dir=root_dir_path,
        expected_frame=pandas.read_csv(expected_csv_path),
        capsys=capsys,
    )


@pytest.mark.timeout(8)
@pytest.mark.parametrize(
    ("args", "root_dir_path", "subjects_dir", "expected_csv_path"),
    [
        (
            [],
            os.path.join(SUBJECTS_DIR, "bert"),
            os.path.join(SUBJECTS_DIR, "alice"),
            os.path.join(SUBJECTS_DIR, "bert", "freesurfer-hippocampal-volumes.csv"),
        ),
        (
            ["--source-types", "ashs"],
            os.path.join(SUBJECTS_DIR, "bert"),
            os.path.join(SUBJECTS_DIR, "alice"),
            os.path.join(SUBJECTS_DIR, "bert", "ashs-hippocampal-volumes.csv"),
        ),
        (
            [],
            os.path.join(SUBJECTS_DIR, "bert"),
            os.path.abspath(os.sep),
            os.path.join(SUBJECTS_DIR, "bert", "freesurfer-hippocampal-volumes.csv"),
        ),
    ],
)
def test_main_root_dir_overwrite_env(
    capsys, args, root_dir_path, subjects_dir, expected_csv_path
):
    assert_main_volume_frame_equals(
        argv=args + ["--", root_dir_path],
        subjects_dir=subjects_dir,
        expected_frame=pandas.read_csv(expected_csv_path),
        capsys=capsys,
    )


def test_main_root_dir_filename_regex_freesurfer(capsys):
    expected_volume_frame = pandas.read_csv(
        os.path.join(SUBJECTS_DIR, "bert", "freesurfer-hippocampal-volumes.csv")
    )
    assert_main_volume_frame_equals(
        argv=[
            "--freesurfer-hipposf-filename-regex",
            r"^.*-T1-T2\.v10\.txt$",
            os.path.join(SUBJECTS_DIR, "bert"),
        ],
        expected_frame=expected_volume_frame[
            expected_volume_frame["analysis_id"] == "T2"
        ].copy(),
        capsys=capsys,
    )


def test_main_root_dir_filename_regex_ashs(capsys):
    expected_volume_frame = pandas.read_csv(
        os.path.join(SUBJECTS_DIR, "bert", "ashs-hippocampal-volumes.csv")
    )
    assert_main_volume_frame_equals(
        argv=[
            "--ashs-filename-regex",
            r"_nogray_volumes.txt$",
            "--source-types",
            "ashs",
            "--",
            os.path.join(SUBJECTS_DIR, "bert"),
        ],
        expected_frame=expected_volume_frame[
            expected_volume_frame["correction"] == "nogray"
        ].copy(),
        capsys=capsys,
    )


def test_main_root_dir_filename_regex_combined(capsys):
    expected_volume_frame = pandas.read_csv(
        os.path.join(SUBJECTS_DIR, "alice", "all-hippocampal-volumes.csv")
    )
    expected_volume_frame = expected_volume_frame[
        # pylint: disable=singleton-comparison
        (expected_volume_frame["T1_input"] == True)
        | (
            (expected_volume_frame["source_type"] == "ashs")
            & expected_volume_frame["correction"].isnull()
        )
    ]
    assert_main_volume_frame_equals(
        argv=[
            "--ashs-filename-regex",
            r"^alice_left_heur_",
            "--freesurfer-hipposf-filename-regex",
            r"hippoSfVolumes-T1.v10.txt$",
            "--source-types",
            "ashs",
            "freesurfer-hipposf",
            "--",
            os.path.join(SUBJECTS_DIR, "alice"),
        ],
        expected_frame=expected_volume_frame.copy(),
        capsys=capsys,
    )


def test_main_no_files_found(capsys):
    with unittest.mock.patch(
        "sys.argv",
        ["", "--freesurfer-hipposf-filename-regex", r"^21$", "--", SUBJECTS_DIR],
    ):
        assert os.EX_NOINPUT == freesurfer_volume_reader.__main__.main()
    out, err = capsys.readouterr()
    assert not out
    assert err == "Did not find any volume files matching the specified criteria.\n"


def test_main_module_script_no_files_found():
    proc_info = subprocess.run(
        [
            "python",
            "-m",
            "freesurfer_volume_reader",
            "--freesurfer-hipposf-filename-regex",
            r"^21$",
            "--",
            SUBJECTS_DIR,
        ],
        check=False,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    assert os.EX_NOINPUT == proc_info.returncode
    assert not proc_info.stdout
    assert "not find any volume files" in proc_info.stderr.rstrip().decode()


def test_script_no_files_found():
    proc_info = subprocess.run(
        [
            "freesurfer-volume-reader",
            "--freesurfer-hipposf-filename-regex",
            r"^21$",
            "--",
            SUBJECTS_DIR,
        ],
        check=False,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    assert os.EX_NOINPUT == proc_info.returncode
    assert not proc_info.stdout
    assert "not find any volume files" in proc_info.stderr.rstrip().decode()


def test_main_module_script_help():
    subprocess.run(["python", "-m", "freesurfer_volume_reader", "--help"], check=True)


def test_main_module_script_version():
    proc_info = subprocess.run(
        ["python", "-m", "freesurfer_volume_reader", "--version"],
        check=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    assert proc_info.stdout.rstrip() == freesurfer_volume_reader.__version__.encode()
    assert not proc_info.stderr