"""Tests for direct file input (GeoParquet -> PMTiles)."""

import pytest
import geopandas as gpd
from shapely.geometry import Point, box

from freestiler import freestile_file

try:
    from freestiler._freestiler import _freestile_file  # noqa: F401

    _HAS_GEOPARQUET = True
except ImportError:
    _HAS_GEOPARQUET = False

try:
    from freestiler._freestiler import _freestile_duckdb  # noqa: F401

    _HAS_DUCKDB = True
except ImportError:
    _HAS_DUCKDB = False


def _require_pyarrow() -> None:
    pytest.importorskip("pyarrow.parquet", reason="pyarrow is required for parquet fixtures")


requires_geoparquet = pytest.mark.skipif(
    not _HAS_GEOPARQUET, reason="GeoParquet feature not compiled"
)
requires_duckdb = pytest.mark.skipif(
    not _HAS_DUCKDB, reason="DuckDB feature not compiled"
)


@pytest.fixture
def parquet_file(tmp_path):
    """Create a small GeoParquet fixture."""
    _require_pyarrow()
    gdf = gpd.GeoDataFrame(
        {
            "name": ["a", "b", "c"],
            "value": [1.0, 2.0, 3.0],
            "count": [10, 20, 30],
        },
        geometry=[
            box(-80, 35, -78, 37),
            box(-82, 34, -79, 36),
            box(-84, 33, -81, 35),
        ],
        crs="EPSG:4326",
    )
    path = tmp_path / "test.parquet"
    gdf.to_parquet(path)
    return path


@pytest.fixture
def point_parquet(tmp_path):
    """Create a small point GeoParquet fixture."""
    _require_pyarrow()
    gdf = gpd.GeoDataFrame(
        {"label": ["p1", "p2", "p3"], "score": [10.5, 20.3, 30.1]},
        geometry=[Point(-78.6, 35.8), Point(-80.2, 36.1), Point(-82.5, 34.2)],
        crs="EPSG:4326",
    )
    path = tmp_path / "points.parquet"
    gdf.to_parquet(path)
    return path


@pytest.fixture
def gpkg_file(tmp_path):
    """Create a small GeoPackage fixture for DuckDB-backed file input."""
    gdf = gpd.GeoDataFrame(
        {
            "name": ["a", "b", "c"],
            "value": [1.0, 2.0, 3.0],
            "count": [10, 20, 30],
        },
        geometry=[
            box(-80, 35, -78, 37),
            box(-82, 34, -79, 36),
            box(-84, 33, -81, 35),
        ],
        crs="EPSG:4326",
    )
    path = tmp_path / "test.gpkg"
    gdf.to_file(path, driver="GPKG")
    return path


@requires_geoparquet
def test_parquet_to_mvt(tmp_path, parquet_file):
    output = tmp_path / "out.pmtiles"
    result = freestile_file(parquet_file, output, tile_format="mvt", max_zoom=6, quiet=True)
    assert result.exists()
    assert result.stat().st_size > 0


@requires_geoparquet
def test_parquet_to_mlt(tmp_path, parquet_file):
    output = tmp_path / "out.pmtiles"
    result = freestile_file(parquet_file, output, tile_format="mlt", max_zoom=6, quiet=True)
    assert result.exists()
    assert result.stat().st_size > 0


@requires_geoparquet
def test_parquet_points(tmp_path, point_parquet):
    output = tmp_path / "pts.pmtiles"
    result = freestile_file(point_parquet, output, max_zoom=6, quiet=True)
    assert result.exists()
    assert result.stat().st_size > 0


@requires_geoparquet
def test_parquet_layer_name(tmp_path, parquet_file):
    output = tmp_path / "custom.pmtiles"
    result = freestile_file(
        parquet_file, output, layer_name="my_layer", max_zoom=4, quiet=True
    )
    assert result.exists()


@requires_geoparquet
def test_parquet_overwrite(tmp_path, parquet_file):
    output = tmp_path / "out.pmtiles"
    freestile_file(parquet_file, output, max_zoom=4, quiet=True)
    freestile_file(parquet_file, output, max_zoom=4, quiet=True, overwrite=True)
    assert output.exists()


@requires_geoparquet
def test_parquet_no_overwrite(tmp_path, parquet_file):
    output = tmp_path / "out.pmtiles"
    freestile_file(parquet_file, output, max_zoom=4, quiet=True)
    with pytest.raises(FileExistsError):
        freestile_file(parquet_file, output, max_zoom=4, quiet=True, overwrite=False)


def test_parquet_missing_file(tmp_path):
    output = tmp_path / "out.pmtiles"
    with pytest.raises(FileNotFoundError):
        freestile_file(tmp_path / "nonexistent.parquet", output, quiet=True)


def test_parquet_invalid_format(tmp_path, parquet_file):
    output = tmp_path / "out.pmtiles"
    with pytest.raises(ValueError, match="tile_format"):
        freestile_file(parquet_file, output, tile_format="xyz", quiet=True)


@requires_geoparquet
def test_file_engine_auto_parquet(tmp_path, parquet_file):
    """Auto engine routes .parquet files to geoparquet."""
    output = tmp_path / "auto.pmtiles"
    result = freestile_file(parquet_file, output, engine="auto", max_zoom=6, quiet=True)
    assert result.exists()
    assert result.stat().st_size > 0


@requires_duckdb
def test_file_engine_duckdb(tmp_path, gpkg_file):
    """Explicit engine='duckdb' on a GDAL-readable spatial file."""
    output = tmp_path / "duckdb.pmtiles"
    result = freestile_file(gpkg_file, output, engine="duckdb", max_zoom=6, quiet=True)
    assert result.exists()
    assert result.stat().st_size > 0


def test_file_engine_invalid(tmp_path, parquet_file):
    output = tmp_path / "out.pmtiles"
    with pytest.raises(ValueError, match="engine"):
        freestile_file(parquet_file, output, engine="bad", quiet=True)
