"""Tests for the pure MPR/orientation geometry used by the GUI (no VTK/Qt)."""
import numpy as np
from sulcora.volume import Volume
from sulcora import mpr


def _vol(affine, shape=(20, 24, 28)):
    return Volume(np.zeros(shape, np.float32), affine)


def test_world_axis_letter_identity_ras():
    aff = np.eye(4)                                   # RAS+: +x=R, +y=A, +z=S
    assert mpr.world_axis_letter(aff, 0, +1) == "R"
    assert mpr.world_axis_letter(aff, 0, -1) == "L"
    assert mpr.world_axis_letter(aff, 1, +1) == "A"
    assert mpr.world_axis_letter(aff, 1, -1) == "P"
    assert mpr.world_axis_letter(aff, 2, +1) == "S"
    assert mpr.world_axis_letter(aff, 2, -1) == "I"


def test_world_axis_letter_respects_flipped_affine():
    # MNI-style affine: increasing i moves toward -x (Left), not Right.
    aff = np.array([[-2, 0, 0, 90], [0, 2, 0, -126], [0, 0, 2, -72], [0, 0, 0, 1]], float)
    assert mpr.world_axis_letter(aff, 0, +1) == "L"   # +i -> Left
    assert mpr.world_axis_letter(aff, 0, -1) == "R"


def test_orientation_labels_identity():
    aff = np.eye(4)
    ax = mpr.orientation_labels(aff, "Axial")
    assert (ax["right"], ax["left"], ax["top"], ax["bottom"]) == ("R", "L", "A", "P")
    cor = mpr.orientation_labels(aff, "Coronal")       # horiz i (R/L), vert k (S/I)
    assert (cor["right"], cor["left"], cor["top"], cor["bottom"]) == ("R", "L", "S", "I")
    sag = mpr.orientation_labels(aff, "Sagittal")      # horiz j (A/P), vert k (S/I)
    assert (sag["right"], sag["left"], sag["top"], sag["bottom"]) == ("A", "P", "S", "I")


def test_orientation_labels_mni_flip():
    aff = np.array([[-2, 0, 0, 90], [0, 2, 0, -126], [0, 0, 2, -72], [0, 0, 0, 1]], float)
    ax = mpr.orientation_labels(aff, "Axial")          # +i is Left now
    assert ax["right"] == "L" and ax["left"] == "R"    # radiological convention
    assert ax["top"] == "A" and ax["bottom"] == "P"


def test_slice_index_for_and_clamp():
    aff = np.eye(4)
    v = _vol(aff, shape=(20, 24, 28))
    # world (5,10,15) -> voxel (5,10,15); axial slice axis is k -> 15
    assert mpr.slice_index_for(v, (5, 10, 15), "Axial") == 15
    assert mpr.slice_index_for(v, (5, 10, 15), "Coronal") == 10    # j
    assert mpr.slice_index_for(v, (5, 10, 15), "Sagittal") == 5    # i
    # out-of-range clamps into [0, n-1]
    assert mpr.slice_index_for(v, (0, 0, 999), "Axial") == 27


def test_slice_indices_all_views():
    v = _vol(np.eye(4), shape=(20, 24, 28))
    idx = mpr.slice_indices(v, (3, 4, 5))
    assert idx == {"Axial": 5, "Coronal": 4, "Sagittal": 3}


def test_crosshair_extents():
    aff = np.eye(4); aff[:3, 3] = [-10, -20, -30]
    v = _vol(aff, shape=(11, 21, 31))                  # spans 10,20,30 mm from origin
    ext = mpr.crosshair_extents(v)
    assert np.allclose(ext["min"], [-10, -20, -30])
    assert np.allclose(ext["max"], [0, 0, 0])
