"""
Tests for Training Export with uniform expand_bbox integration.

Tests the export endpoint's integration with uniform bbox expansion.
"""

import pytest
from unittest.mock import MagicMock, patch
from uuid import uuid4

from shared.bbox import expand_bbox, UNIFORM_PAD
from shared.fields import CLASS_NAMES, FIELD_CLASS_IDS


class TestExpandBboxForExport:
    """Tests for expand_bbox integration in export workflow."""

    def test_expand_bbox_converts_normalized_to_pixel_and_back(self):
        """Verify expand_bbox works with pixel-to-normalized conversion."""
        x_center_norm = 0.5
        y_center_norm = 0.5
        width_norm = 0.1
        height_norm = 0.05

        img_width = 2480
        img_height = 3508

        x_center_px = x_center_norm * img_width
        y_center_px = y_center_norm * img_height
        width_px = width_norm * img_width
        height_px = height_norm * img_height

        x0 = x_center_px - width_px / 2
        y0 = y_center_px - height_px / 2
        x1 = x_center_px + width_px / 2
        y1 = y_center_px + height_px / 2

        ex0, ey0, ex1, ey1 = expand_bbox(
            bbox=(x0, y0, x1, y1),
            image_width=img_width,
            image_height=img_height,
        )

        assert ex0 < x0
        assert ey0 < y0
        assert ex1 > x1
        assert ey1 > y1

        new_x_center = (ex0 + ex1) / 2 / img_width
        new_y_center = (ey0 + ey1) / 2 / img_height
        new_width = (ex1 - ex0) / img_width
        new_height = (ey1 - ey0) / img_height

        assert 0 <= new_x_center <= 1
        assert 0 <= new_y_center <= 1
        assert 0 <= new_width <= 1
        assert 0 <= new_height <= 1

    def test_expand_bbox_uniform_for_all_sources(self):
        """Verify all annotation sources get the same uniform expansion."""
        bbox = (100, 100, 200, 150)
        img_width = 2480
        img_height = 3508

        # All sources now get the same uniform expansion
        result = expand_bbox(
            bbox=bbox,
            image_width=img_width,
            image_height=img_height,
        )

        expected = (
            100 - UNIFORM_PAD,
            100 - UNIFORM_PAD,
            200 + UNIFORM_PAD,
            150 + UNIFORM_PAD,
        )
        assert result == expected

    def test_expand_bbox_all_field_types_work(self):
        """Verify expand_bbox works for all field types (same result)."""
        bbox = (100, 100, 200, 150)
        img_width = 2480
        img_height = 3508

        # All fields should produce the same result with uniform padding
        first_result = expand_bbox(
            bbox=bbox,
            image_width=img_width,
            image_height=img_height,
        )

        assert len(first_result) == 4
        x0, y0, x1, y1 = first_result
        assert x0 >= 0
        assert y0 >= 0
        assert x1 <= img_width
        assert y1 <= img_height
        assert x1 > x0
        assert y1 > y0


class TestExportAnnotationExpansion:
    """Tests for annotation expansion in export workflow."""

    def test_annotation_bbox_conversion_workflow(self):
        """Test full annotation bbox conversion workflow."""
        class MockAnnotation:
            class_id = FIELD_CLASS_IDS["invoice_number"]
            class_name = "invoice_number"
            x_center = 0.3
            y_center = 0.2
            width = 0.15
            height = 0.03
            source = "auto"

        ann = MockAnnotation()
        img_width = 2480
        img_height = 3508

        half_w = (ann.width * img_width) / 2
        half_h = (ann.height * img_height) / 2
        x0 = ann.x_center * img_width - half_w
        y0 = ann.y_center * img_height - half_h
        x1 = ann.x_center * img_width + half_w
        y1 = ann.y_center * img_height + half_h

        ex0, ey0, ex1, ey1 = expand_bbox(
            bbox=(x0, y0, x1, y1),
            image_width=img_width,
            image_height=img_height,
        )

        new_x_center = (ex0 + ex1) / 2 / img_width
        new_y_center = (ey0 + ey1) / 2 / img_height
        new_width = (ex1 - ex0) / img_width
        new_height = (ey1 - ey0) / img_height

        assert new_width > ann.width
        assert new_height > ann.height

        assert 0 <= new_x_center <= 1
        assert 0 <= new_y_center <= 1
        assert 0 < new_width <= 1
        assert 0 < new_height <= 1

    def test_export_applies_uniform_expansion_to_all_annotations(self):
        """Test that export applies uniform expansion to all annotations."""
        annotations = [
            {"class_name": "invoice_number", "source": "auto", "x_center": 0.3, "y_center": 0.2, "width": 0.05, "height": 0.02},
            {"class_name": "ocr_number", "source": "manual", "x_center": 0.5, "y_center": 0.8, "width": 0.05, "height": 0.02},
            {"class_name": "amount", "source": "imported", "x_center": 0.7, "y_center": 0.5, "width": 0.05, "height": 0.02},
        ]

        img_width = 2480
        img_height = 3508

        expanded_annotations = []
        for ann in annotations:
            half_w = (ann["width"] * img_width) / 2
            half_h = (ann["height"] * img_height) / 2
            x0 = ann["x_center"] * img_width - half_w
            y0 = ann["y_center"] * img_height - half_h
            x1 = ann["x_center"] * img_width + half_w
            y1 = ann["y_center"] * img_height + half_h

            ex0, ey0, ex1, ey1 = expand_bbox(
                bbox=(x0, y0, x1, y1),
                image_width=img_width,
                image_height=img_height,
            )

            expanded_annotations.append({
                "class_name": ann["class_name"],
                "source": ann["source"],
                "x_center": (ex0 + ex1) / 2 / img_width,
                "y_center": (ey0 + ey1) / 2 / img_height,
                "width": (ex1 - ex0) / img_width,
                "height": (ey1 - ey0) / img_height,
            })

        # All annotations get the same expansion
        tolerance = 0.01
        for orig, exp in zip(annotations, expanded_annotations):
            assert exp["width"] >= orig["width"] * (1 - tolerance)
            assert exp["height"] >= orig["height"] * (1 - tolerance)


class TestExpandBboxEdgeCases:
    """Tests for edge cases in export bbox expansion."""

    def test_bbox_at_image_edge_left(self):
        bbox = (0, 100, 50, 150)

        result = expand_bbox(bbox=bbox, image_width=2480, image_height=3508)

        assert result[0] >= 0

    def test_bbox_at_image_edge_right(self):
        bbox = (2400, 100, 2480, 150)

        result = expand_bbox(bbox=bbox, image_width=2480, image_height=3508)

        assert result[2] <= 2480

    def test_bbox_at_image_edge_top(self):
        bbox = (100, 0, 200, 50)

        result = expand_bbox(bbox=bbox, image_width=2480, image_height=3508)

        assert result[1] >= 0

    def test_bbox_at_image_edge_bottom(self):
        bbox = (100, 3400, 200, 3508)

        result = expand_bbox(bbox=bbox, image_width=2480, image_height=3508)

        assert result[3] <= 3508

    def test_very_small_bbox(self):
        bbox = (100, 100, 105, 105)

        result = expand_bbox(bbox=bbox, image_width=2480, image_height=3508)

        assert result[2] > result[0]
        assert result[3] > result[1]
