import numpy as np
from django.test import SimpleTestCase

from processing.algorithms import (
    LAPLACIAN_MASK,
    ProcessingError,
    average_images,
    gamma,
    histogram_equalization,
    median_filter,
    negative,
    roberts,
    sobel,
    subtract_images,
    verify_registration,
)


class AlgorithmTests(SimpleTestCase):
    def test_negative_transform_uses_l_minus_one(self):
        image = np.array([[[0, 127, 255]]], dtype=np.uint8)
        result = negative(image, {})
        np.testing.assert_array_equal(result, np.array([[[255, 128, 0]]], dtype=np.uint8))

    def test_gamma_identity(self):
        image = np.array([[[0, 128, 255]]], dtype=np.uint8)
        result = gamma(image, {"gamma": 1, "c": 1})
        np.testing.assert_array_equal(result, image)

    def test_laplacian_mask_sums_to_zero(self):
        self.assertEqual(int(LAPLACIAN_MASK.sum()), 0)

    def test_histogram_equalization_spreads_two_levels(self):
        image = np.array([[0, 0], [255, 255]], dtype=np.uint8)
        result = histogram_equalization(image, {})
        np.testing.assert_array_equal(result, image)

    def test_median_removes_impulse_noise(self):
        image = np.full((3, 3, 3), 100, dtype=np.uint8)
        image[1, 1] = 255
        result = median_filter(image, {"size": 3})
        self.assertEqual(int(result[1, 1, 0]), 100)

    def test_gradient_outputs_are_display_normalized(self):
        image = np.zeros((5, 5, 3), dtype=np.uint8)
        image[:, 3:] = 255
        self.assertEqual(sobel(image, {}).dtype, np.uint8)
        self.assertEqual(roberts(image, {}).dtype, np.uint8)

    def test_arithmetic_requires_registered_shapes(self):
        left = np.zeros((2, 2, 3), dtype=np.uint8)
        right = np.zeros((3, 2, 3), dtype=np.uint8)
        with self.assertRaises(ProcessingError):
            verify_registration([left, right])

    def test_average_and_subtraction(self):
        left = np.zeros((2, 2, 3), dtype=np.uint8)
        right = np.full((2, 2, 3), 100, dtype=np.uint8)
        self.assertEqual(int(average_images([left, right])[0, 0, 0]), 50)
        self.assertEqual(int(subtract_images(left, right)[0, 0, 0]), 0)
