import cv2
import numpy as np

from backend.segmentation import compare_frame, segment_frame


def synthetic_frame(shift: int = 0) -> np.ndarray:
    frame = np.full((220, 320, 3), 158, dtype=np.uint8)
    noise = np.random.default_rng(42 + shift).normal(0, 6, frame.shape[:2]).astype(np.int16)
    gray = np.clip(frame[:, :, 0].astype(np.int16) + noise, 0, 255).astype(np.uint8)
    frame = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
    points = np.array([[28, 142 + shift], [92, 108 + shift], [174, 124 + shift], [286, 80 + shift]], dtype=np.int32)
    cv2.polylines(frame, [points.reshape((-1, 1, 2))], False, (32, 32, 32), 2, cv2.LINE_AA)
    return frame


def assert_output(output):
    assert output.mask.shape[:2] == (220, 320)
    assert output.overlay.shape == (220, 320, 3)
    assert output.metrics["mask_pixels"] > 0
    assert 0 <= output.metrics["coverage"] <= 1


def test_segmentation_methods_return_non_empty_masks():
    previous = synthetic_frame(0)
    current = synthetic_frame(2)
    for method in ["hessian_ridge", "edge_morphology", "temporal_difference", "fusion"]:
        assert_output(segment_frame(current, method=method, previous_frame=previous, sensitivity=0.7))


def test_compare_frame_returns_all_methods():
    outputs = compare_frame(synthetic_frame(1), synthetic_frame(0), sensitivity=0.65)
    assert [item.method for item in outputs] == [
        "hessian_ridge",
        "edge_morphology",
        "temporal_difference",
        "fusion",
    ]
    assert all(item.metrics["mask_pixels"] > 0 for item in outputs)
