"""Unit tests for the grid-tiling / geometry helpers (INDL-49). No DB required."""
import pytest

from src.core.exceptions import ValidationError
from src.core.utils.geometry import (
    build_plot_grid,
    validate_polygon_geojson,
)


def test_build_grid_count_and_non_overlap():
    polys = build_plot_grid(
        origin_lat=45.4215, origin_lng=-75.6972,
        rows=5, cols=4, plot_width_m=1.2, plot_length_m=2.4, gap_m=0.3,
    )
    assert len(polys) == 20
    # Every polygon is a valid rectangle with positive area.
    assert all(p.is_valid and p.area > 0 for p in polys)
    # No two plots overlap (they may touch only with gap=0).
    for i in range(len(polys)):
        for j in range(i + 1, len(polys)):
            inter = polys[i].intersection(polys[j])
            assert inter.area == pytest.approx(0.0, abs=1e-12)


def test_build_grid_sw_anchor_grows_north_east():
    """Default 'sw' anchor: the origin is the grid's south-west corner, so every
    cell lies north (>= lat) and east (>= lng) of it."""
    origin_lat, origin_lng = 45.0, -75.0
    polys = build_plot_grid(
        origin_lat=origin_lat, origin_lng=origin_lng,
        rows=4, cols=4, plot_width_m=2, plot_length_m=2, gap_m=0.3,
    )
    for p in polys:
        minx, miny, _, _ = p.bounds  # (lng, lat)
        assert miny >= origin_lat - 1e-9
        assert minx >= origin_lng - 1e-9


def test_build_grid_center_anchor_centers_on_origin():
    """'center' anchor: the origin is the CENTRE of the grid, so the grid's overall
    bounding box is centred on it — plots straddle the origin instead of spilling
    off to the north-east. Regression for the 'plots render outside the section
    boundary' bug (grid was anchored SW at the section centroid)."""
    origin_lat, origin_lng = 45.0, -75.0
    polys = build_plot_grid(
        origin_lat=origin_lat, origin_lng=origin_lng,
        rows=4, cols=4, plot_width_m=2, plot_length_m=2, gap_m=0.3,
        anchor="center",
    )
    minx = min(p.bounds[0] for p in polys)
    miny = min(p.bounds[1] for p in polys)
    maxx = max(p.bounds[2] for p in polys)
    maxy = max(p.bounds[3] for p in polys)
    # Bounding-box centre coincides with the origin (within float projection error).
    assert (minx + maxx) / 2 == pytest.approx(origin_lng, abs=1e-6)
    assert (miny + maxy) / 2 == pytest.approx(origin_lat, abs=1e-6)
    # And the grid genuinely straddles the origin on both axes.
    assert minx < origin_lng < maxx
    assert miny < origin_lat < maxy


def test_build_grid_zero_gap_touches_but_no_overlap():
    polys = build_plot_grid(
        origin_lat=0.0, origin_lng=0.0,
        rows=2, cols=2, plot_width_m=2, plot_length_m=2, gap_m=0.0,
    )
    assert len(polys) == 4
    for i in range(len(polys)):
        for j in range(i + 1, len(polys)):
            assert polys[i].intersection(polys[j]).area == pytest.approx(0.0, abs=1e-12)


def test_validate_rejects_non_polygon():
    with pytest.raises(ValidationError):
        validate_polygon_geojson({"type": "Point", "coordinates": [0, 0]})


def test_validate_rejects_too_few_points():
    with pytest.raises(ValidationError):
        validate_polygon_geojson({"type": "Polygon", "coordinates": [[[0, 0], [1, 1]]]})


def test_validate_accepts_valid_polygon():
    geom = validate_polygon_geojson({
        "type": "Polygon",
        "coordinates": [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]],
    })
    assert geom.is_valid and geom.area > 0
