# Authors: The MNE-Python contributors.
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.

import re

import numpy as np
import pytest

from mne import (
    SourceEstimate,
    VolSourceEstimate,
    VolVectorSourceEstimate,
    compute_covariance,
    compute_source_morph,
    make_fixed_length_epochs,
    make_forward_solution,
    read_bem_solution,
    read_forward_solution,
    read_trans,
    setup_volume_source_space,
)
from mne.datasets import testing
from mne.io import read_raw_fif
from mne.minimum_norm import apply_inverse, make_inverse_operator
from mne.utils import _record_warnings, catch_logging
from mne.viz import plot_volume_source_estimates
from mne.viz.utils import _fake_click, _fake_keypress

data_dir = testing.data_path(download=False)
subjects_dir = data_dir / "subjects"
fwd_fname = data_dir / "MEG" / "sample" / "sample_audvis_trunc-meg-vol-7-fwd.fif"


@pytest.mark.slowtest  # can be slow on OSX
@testing.requires_testing_data
@pytest.mark.parametrize(
    "mode, stype, init_t, want_t, init_p, want_p, bg_img",
    [
        ("glass_brain", "s", None, 2, None, (-30.9, 18.4, 56.7), None),
        ("stat_map", "vec", 1, 1, None, (15.7, 16.0, -6.3), None),
        ("glass_brain", "vec", None, 1, (10, -10, 20), (6.6, -9.0, 19.9), None),
        ("stat_map", "s", 1, 1, (-10, 5, 10), (-12.3, 2.0, 7.7), "brain.mgz"),
    ],
)
def test_plot_volume_source_estimates_basic(
    mode, stype, init_t, want_t, init_p, want_p, bg_img
):
    """Test interactive plotting of volume source estimates."""
    pytest.importorskip("nibabel")
    pytest.importorskip("dipy")
    pytest.importorskip("nilearn")
    forward = read_forward_solution(fwd_fname)
    sample_src = forward["src"]
    if init_p is not None:
        init_p = np.array(init_p) / 1000.0

    vertices = [s["vertno"] for s in sample_src]
    n_verts = sum(len(v) for v in vertices)
    n_time = 2
    data = np.random.RandomState(0).rand(n_verts, n_time)

    if stype == "vec":
        stc = VolVectorSourceEstimate(
            np.tile(data[:, np.newaxis], (1, 3, 1)), vertices, 1, 1
        )
    else:
        assert stype == "s"
        stc = VolSourceEstimate(data, vertices, 1, 1)
    # sometimes get scalars/index warning
    with _record_warnings():
        with catch_logging(verbose="debug") as log:
            fig = stc.plot(
                sample_src,
                subject="sample",
                subjects_dir=subjects_dir,
                mode=mode,
                initial_time=init_t,
                initial_pos=init_p,
                bg_img=bg_img,
                verbose=True,
            )
    log = log.getvalue()
    want_str = f"t = {want_t:0.3f} s"
    assert want_str in log, (want_str, init_t)
    want_str = f"({want_p[0]:0.1f}, {want_p[1]:0.1f}, {want_p[2]:0.1f}) mm"
    assert want_str in log, (want_str, init_p)
    for ax_idx in [0, 2, 3, 4]:
        _fake_click(fig, fig.axes[ax_idx], (0.5, 0.5))
    _fake_keypress(fig, "left")
    _fake_keypress(fig, "shift+right")
    if bg_img is not None:
        with pytest.raises(FileNotFoundError, match="MRI file .* not found"):
            stc.plot(
                sample_src,
                subject="sample",
                subjects_dir=subjects_dir,
                mode="stat_map",
                bg_img="junk.mgz",
            )
    use_ax = None
    for ax in fig.axes:
        if ax.get_xlabel().startswith("Time"):
            use_ax = ax
            break
    assert use_ax is not None
    label = use_ax.get_legend().get_texts()[0].get_text()
    assert re.match("[0-9]*", label) is not None, label


@pytest.mark.slowtest  # can be slow on OSX
@testing.requires_testing_data
def test_plot_volume_source_estimates_morph():
    """Test interactive plotting of volume source estimates with morph."""
    pytest.importorskip("nibabel")
    pytest.importorskip("dipy")
    pytest.importorskip("nilearn")
    forward = read_forward_solution(fwd_fname)
    sample_src = forward["src"]
    vertices = [s["vertno"] for s in sample_src]
    n_verts = sum(len(v) for v in vertices)
    n_time = 2
    data = np.random.RandomState(0).rand(n_verts, n_time)
    stc = VolSourceEstimate(data, vertices, 1, 1)
    sample_src[0]["subject_his_id"] = "sample"  # old src
    morph = compute_source_morph(
        sample_src, "sample", "fsaverage", zooms=5, subjects_dir=subjects_dir
    )
    initial_pos = (-0.05, -0.01, -0.006)
    # sometimes get scalars/index warning
    with _record_warnings():
        with catch_logging() as log:
            stc.plot(
                morph,
                subjects_dir=subjects_dir,
                mode="glass_brain",
                initial_pos=initial_pos,
                verbose=True,
            )
    log = log.getvalue()
    assert "t = 1.000 s" in log
    assert "(-52.0, -8.0, -7.0) mm" in log

    with pytest.raises(ValueError, match="Allowed values are"):
        stc.plot(sample_src, "sample", subjects_dir, mode="abcd")
    vertices.append([])
    surface_stc = SourceEstimate(data, vertices, 1, 1)
    with pytest.raises(TypeError, match="an instance of VolSourceEstimate"):
        plot_volume_source_estimates(surface_stc, sample_src, "sample", subjects_dir)
    with pytest.raises(ValueError, match="Negative colormap limits"):
        stc.plot(
            sample_src, "sample", subjects_dir, clim=dict(lims=[-1, 2, 3], kind="value")
        )


@testing.requires_testing_data
def test_plot_volume_source_estimates_on_vol_labels():
    """Test plot of source estimate on srcs setup on 2 labels."""
    pytest.importorskip("nibabel")
    pytest.importorskip("dipy")
    pytest.importorskip("nilearn")
    raw = read_raw_fif(
        data_dir / "MEG" / "sample" / "sample_audvis_trunc_raw.fif", preload=False
    )
    raw.pick("meg").crop(0, 10)
    raw.pick(raw.ch_names[::2]).del_proj().load_data()
    epochs = make_fixed_length_epochs(raw, preload=True).apply_baseline((None, None))
    evoked = epochs.average()
    subject = "sample"
    bem = read_bem_solution(
        subjects_dir / f"{subject}" / "bem" / "sample-320-bem-sol.fif"
    )
    pos = 25.0  # spacing in mm
    volume_label = [
        "Right-Cerebral-Cortex",
        "Left-Cerebral-Cortex",
    ]
    src = setup_volume_source_space(
        subject,
        subjects_dir=subjects_dir,
        pos=pos,
        mri=subjects_dir / subject / "mri" / "aseg.mgz",
        bem=bem,
        volume_label=volume_label,
        add_interpolator=False,
    )
    trans = read_trans(data_dir / "MEG" / "sample" / "sample_audvis_trunc-trans.fif")
    fwd = make_forward_solution(
        evoked.info,
        trans,
        src,
        bem,
        meg=True,
        eeg=False,
        mindist=0,
        n_jobs=1,
    )
    cov = compute_covariance(
        epochs,
        tmin=None,
        tmax=None,
        method="empirical",
    )
    inverse_operator = make_inverse_operator(evoked.info, fwd, cov, loose=1, depth=0.8)
    stc = apply_inverse(
        evoked, inverse_operator, 1.0 / 3**2, method="sLORETA", pick_ori=None
    )
    stc.plot(src, subject, subjects_dir, initial_time=0.03)
