"""
Tests for expand_bbox function with uniform pixel padding.

Verifies that bbox expansion adds uniform padding on all sides,
clamps to image boundaries, and returns integer tuples.
"""

import pytest

from shared.bbox import expand_bbox
from shared.bbox.scale_strategy import UNIFORM_PAD


class TestExpandBboxUniformPadding:
    """Tests for uniform padding on all sides."""

    def test_adds_uniform_pad_on_all_sides(self):
        """Verify default pad is applied equally on all four sides."""
        bbox = (100, 200, 300, 250)

        result = expand_bbox(
            bbox=bbox,
            image_width=1000,
            image_height=1000,
        )

        assert result == (
            100 - UNIFORM_PAD,
            200 - UNIFORM_PAD,
            300 + UNIFORM_PAD,
            250 + UNIFORM_PAD,
        )

    def test_custom_pad_value(self):
        """Verify custom pad overrides default."""
        bbox = (100, 200, 300, 250)

        result = expand_bbox(
            bbox=bbox,
            image_width=1000,
            image_height=1000,
            pad=20,
        )

        assert result == (80, 180, 320, 270)

    def test_zero_pad_returns_original(self):
        """Verify pad=0 returns original bbox as integers."""
        bbox = (100, 200, 300, 250)

        result = expand_bbox(
            bbox=bbox,
            image_width=1000,
            image_height=1000,
            pad=0,
        )

        assert result == (100, 200, 300, 250)

    def test_all_field_types_get_same_padding(self):
        """Verify no field-specific expansion -- same result regardless of field."""
        bbox = (100, 200, 300, 250)

        result_a = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)
        result_b = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        assert result_a == result_b


class TestExpandBboxImageBoundaryClamping:
    """Tests for clamping to image boundaries."""

    def test_clamps_x0_to_zero(self):
        bbox = (5, 200, 100, 250)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        assert result[0] == 0

    def test_clamps_y0_to_zero(self):
        bbox = (100, 3, 300, 50)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        assert result[1] == 0

    def test_clamps_x1_to_image_width(self):
        bbox = (900, 200, 995, 250)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        assert result[2] == 1000

    def test_clamps_y1_to_image_height(self):
        bbox = (100, 900, 300, 995)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        assert result[3] == 1000

    def test_corner_bbox_clamps_multiple_sides(self):
        """Bbox near top-left corner clamps both x0 and y0."""
        bbox = (2, 3, 50, 60)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        assert result[0] == 0
        assert result[1] == 0
        assert result[2] == 50 + UNIFORM_PAD
        assert result[3] == 60 + UNIFORM_PAD


class TestExpandBboxReturnType:
    """Tests for return type and value format."""

    def test_returns_tuple_of_four_ints(self):
        bbox = (100.5, 200.3, 300.7, 250.9)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        assert isinstance(result, tuple)
        assert len(result) == 4
        assert all(isinstance(v, int) for v in result)

    def test_float_bbox_floors_correctly(self):
        """Verify float coordinates are converted to int properly."""
        bbox = (100.7, 200.3, 300.2, 250.8)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000, pad=0)

        # int() truncates toward zero
        assert result == (100, 200, 300, 250)

    def test_returns_valid_bbox_ordering(self):
        """Verify x0 < x1 and y0 < y1."""
        bbox = (100, 200, 300, 250)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        x0, y0, x1, y1 = result
        assert x0 < x1
        assert y0 < y1


class TestExpandBboxEdgeCases:
    """Tests for edge cases."""

    def test_small_bbox_with_large_pad(self):
        """Pad larger than bbox still works correctly."""
        bbox = (100, 200, 105, 203)  # 5x3 pixel bbox

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000, pad=50)

        assert result == (50, 150, 155, 253)

    def test_bbox_at_origin(self):
        bbox = (0, 0, 50, 30)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        assert result[0] == 0
        assert result[1] == 0

    def test_bbox_at_image_edge(self):
        bbox = (950, 970, 1000, 1000)

        result = expand_bbox(bbox=bbox, image_width=1000, image_height=1000)

        assert result[2] == 1000
        assert result[3] == 1000
