"""Tests for tondortools.geo — BoundingBox pure-math surface and create_extent_wkt."""
import pytest

from tondortools.geo import BoundingBox, create_extent_wkt


# ---------------------------------------------------------------------------
# BoundingBox — construction
# ---------------------------------------------------------------------------

class TestBoundingBoxInit:
    def test_stores_coords_and_epsg(self):
        bb = BoundingBox(10.0, 20.0, 30.0, 40.0, 4326)
        assert bb.xmin == 10.0
        assert bb.ymin == 20.0
        assert bb.xmax == 30.0
        assert bb.ymax == 40.0
        assert bb.epsg == 4326

    def test_swaps_x_if_min_greater_than_max(self):
        bb = BoundingBox(30.0, 20.0, 10.0, 40.0, 4326)
        assert bb.xmin == 10.0
        assert bb.xmax == 30.0

    def test_swaps_y_if_min_greater_than_max(self):
        bb = BoundingBox(10.0, 50.0, 30.0, 20.0, 4326)
        assert bb.ymin == 20.0
        assert bb.ymax == 50.0

    def test_accepts_integers(self):
        bb = BoundingBox(0, 0, 100, 100, 32632)
        assert bb.xmax == 100
        assert bb.epsg == 32632

    def test_repr_contains_coords(self):
        bb = BoundingBox(1.0, 2.0, 3.0, 4.0, 4326)
        r = repr(bb)
        assert "BoundingBox" in r
        assert "4326" in r


# ---------------------------------------------------------------------------
# BoundingBox.pixel_count
# ---------------------------------------------------------------------------

class TestBoundingBoxPixelCount:
    def test_10x10_with_size_1(self):
        bb = BoundingBox(0, 0, 10, 10, 4326)
        assert bb.pixel_count(1) == 100

    def test_10x10_with_size_2(self):
        bb = BoundingBox(0, 0, 10, 10, 4326)
        assert bb.pixel_count(2) == 25  # 5 * 5

    def test_non_square(self):
        bb = BoundingBox(0, 0, 20, 10, 4326)
        assert bb.pixel_count(1) == 200  # 20 * 10

    def test_result_truncates_toward_zero(self):
        # int() truncates; 7 / 2 = 3 (not 4)
        bb = BoundingBox(0, 0, 7, 7, 4326)
        assert bb.pixel_count(2) == 9  # int(7/2) * int(7/2) = 3 * 3

    def test_zero_dimension_yields_zero(self):
        bb = BoundingBox(0, 0, 0, 10, 4326)
        assert bb.pixel_count(1) == 0


# ---------------------------------------------------------------------------
# BoundingBox.enlarge
# ---------------------------------------------------------------------------

class TestBoundingBoxEnlarge:
    def test_expands_all_sides(self):
        bb = BoundingBox(10, 20, 30, 40, 4326)
        enlarged = bb.enlarge(5)
        assert enlarged.xmin == 5
        assert enlarged.ymin == 15
        assert enlarged.xmax == 35
        assert enlarged.ymax == 45

    def test_returns_new_instance(self):
        bb = BoundingBox(10, 20, 30, 40, 4326)
        enlarged = bb.enlarge(5)
        assert enlarged is not bb

    def test_preserves_epsg(self):
        bb = BoundingBox(0, 0, 100, 100, 32632)
        assert bb.enlarge(10).epsg == 32632

    def test_zero_size_returns_same_coords(self):
        bb = BoundingBox(10, 20, 30, 40, 4326)
        enlarged = bb.enlarge(0)
        assert enlarged.xmin == bb.xmin
        assert enlarged.xmax == bb.xmax


# ---------------------------------------------------------------------------
# BoundingBox.enlarge_to_grid
# ---------------------------------------------------------------------------

class TestBoundingBoxEnlargeToGrid:
    def test_already_aligned(self):
        bb = BoundingBox(0, 0, 100, 100, 4326)
        snapped = bb.enlarge_to_grid(10)
        assert snapped.xmin == 0
        assert snapped.ymin == 0
        assert snapped.xmax == 100
        assert snapped.ymax == 100

    def test_snaps_min_down_and_max_up(self):
        bb = BoundingBox(3, 7, 23, 37, 4326)
        snapped = bb.enlarge_to_grid(10)
        assert snapped.xmin == 0    # floor(3/10)*10
        assert snapped.ymin == 0    # floor(7/10)*10
        assert snapped.xmax == 30   # ceil(23/10)*10
        assert snapped.ymax == 40   # ceil(37/10)*10

    def test_preserves_epsg(self):
        bb = BoundingBox(3, 7, 23, 37, 32632)
        assert bb.enlarge_to_grid(10).epsg == 32632

    def test_non_integer_grid_size(self):
        bb = BoundingBox(0.03, 0.07, 0.23, 0.37, 4326)
        snapped = bb.enlarge_to_grid(0.1)
        assert abs(snapped.xmin - 0.0) < 1e-9
        assert abs(snapped.xmax - 0.3) < 1e-9


# ---------------------------------------------------------------------------
# BoundingBox.transform (same-epsg short-circuit only — no real GDAL)
# ---------------------------------------------------------------------------

class TestBoundingBoxTransform:
    def test_same_epsg_returns_self(self):
        bb = BoundingBox(0, 0, 10, 10, 4326)
        result = bb.transform(4326)
        assert result is bb


# ---------------------------------------------------------------------------
# create_extent_wkt (smoke test — ogr is mocked so output is a MagicMock)
# ---------------------------------------------------------------------------

class TestCreateExtentWkt:
    def test_does_not_raise(self):
        extent = {"xmin": "10.0", "ymin": "20.0", "xmax": "30.0", "ymax": "40.0"}
        # ogr is mocked; ExportToWkt() returns a MagicMock — just verify no crash.
        result = create_extent_wkt(extent, 4326)
        assert result is not None
