"""Integration tests for end-to-end catalog generation and spatial resolution."""

import json
import tempfile
from pathlib import Path

import pytest
from shapely.geometry import box

from earthcatalog.spatial_resolver import spatial_resolver


class TestIntegration:
    """Integration tests for schema generation and spatial resolution workflow."""

    def setup_method(self):
        """Set up test fixtures."""
        self.temp_dir = tempfile.mkdtemp()
        self.catalog_path = Path(self.temp_dir) / "test_catalog"
        self.catalog_path.mkdir(exist_ok=True)

    def test_schema_generation_and_spatial_resolution(self):
        """Test schema generation functionality and spatial resolution."""

        # Create a mock schema file (as would be generated by the pipeline)
        mock_schema = {
            "spatial_partitioning": {
                "grid_system": "h3",
                "resolution": 6,
                "coordinate_system": "WGS84 (EPSG:4326)",
                "cell_area_km2_avg": 36.13,
                "cell_edge_length_km_avg": 3.23,
            },
            "global_partitioning": {
                "enabled": True,
                "threshold": 2,
                "description": "Items that span more than 2 spatial cells are stored in global partition",
            },
            "temporal_partitioning": {"scheme": "year-month", "levels": ["year", "month"]},
            "partition_structure": {
                "spatial_partitions": ["861d907dfffffff", "861d90757ffffff"],
                "temporal_partitions": ["2024", "2024-01", "2024-02"],
                "global_partition": True,
                "total_partitions": 12,
            },
            "usage_examples": {
                "query_pattern": "SELECT * FROM read_parquet('{catalog_path}/spatial_partition={{partition_id}}/temporal_partition=2024-*/data.parquet')",
                "description": "Replace {{partition_id}} with resolved spatial partition IDs for efficient querying",
            },
        }

        # Save mock schema file
        schema_file = self.catalog_path / "catalog_schema.json"
        with open(schema_file, "w") as f:
            json.dump(mock_schema, f, indent=2)

        # Test spatial resolution with mock schema
        resolver = spatial_resolver(str(schema_file), str(self.catalog_path))

        # Verify resolver initialization
        assert resolver.grid_system == "h3"
        assert resolver.spatial_config["resolution"] == 6
        assert resolver.global_enabled is True
        assert resolver.global_threshold == 2

        # Test resolution for San Francisco area
        sf_area = box(-122.5, 37.7, -122.0, 38.0)
        sf_partitions = resolver.resolve_partitions(sf_area, overlap=True)

        assert len(sf_partitions) > 0, "Should resolve at least one partition for SF area"

        # Test query path generation (creates mock partition directories for testing)
        for partition_id in sf_partitions[:2]:  # Only test a couple to avoid creating too many dirs
            if partition_id != "global":  # Skip global partition for this test
                partition_dir = self.catalog_path / partition_id
                partition_dir.mkdir(exist_ok=True)

        query_paths = resolver.generate_query_paths(sf_partitions, "2024-*")
        assert isinstance(query_paths, list), "Should return query path list"
        if len(query_paths) > 0:  # Only check content if paths exist
            assert any("2024-*" in path for path in query_paths), "Should contain temporal filter"

        # Test resolution with manual global override
        small_area = box(-122.1, 37.8, -122.05, 37.85)  # Very small area in SF
        small_partitions_no_global = resolver.resolve_partitions(small_area, include_global=False)
        small_partitions_with_global = resolver.resolve_partitions(small_area, include_global=True)

        assert "global" not in small_partitions_no_global, "Manual override should exclude global"
        assert "global" in small_partitions_with_global, "Manual override should include global"

    def test_geojson_schema_and_resolution(self):
        """Test schema generation and resolution with custom GeoJSON grid system."""

        # Create custom GeoJSON tiles structure (as would be in a schema)
        geojson_tiles = {
            "type": "FeatureCollection",
            "features": [
                {
                    "type": "Feature",
                    "id": "tile_001",
                    "properties": {"id": "tile_001"},  # ID should be in properties for resolver
                    "geometry": {
                        "type": "Polygon",
                        "coordinates": [
                            [[-122.5, 37.7], [-122.0, 37.7], [-122.0, 38.0], [-122.5, 38.0], [-122.5, 37.7]]
                        ],
                    },
                },
                {
                    "type": "Feature",
                    "id": "tile_002",
                    "properties": {"id": "tile_002"},  # ID should be in properties for resolver
                    "geometry": {
                        "type": "Polygon",
                        "coordinates": [
                            [[-121.0, 37.0], [-120.5, 37.0], [-120.5, 37.5], [-121.0, 37.5], [-121.0, 37.0]]
                        ],
                    },
                },
            ],
        }

        # Save GeoJSON tiles to a file (as would happen in real usage)
        geojson_file = self.catalog_path / "custom_tiles.geojson"
        with open(geojson_file, "w") as f:
            json.dump(geojson_tiles, f)

        # Create mock schema with GeoJSON grid (matching schema_generator format)
        geojson_schema = {
            "spatial_partitioning": {
                "grid_system": "geojson",
                "geojson_source": str(geojson_file),
                "custom_tiles": {
                    "total_tiles": 2,
                    "tile_ids": ["tile_001", "tile_002"],
                    "source_file": str(geojson_file),
                },
                "coordinate_system": "WGS84 (EPSG:4326)",
            },
            "global_partitioning": {"enabled": False},
            "temporal_partitioning": {"scheme": "year-month", "levels": ["year", "month"]},
            "partition_structure": {
                "spatial_partitions": ["tile_001", "tile_002"],
                "temporal_partitions": ["2024", "2024-01"],
                "global_partition": False,
                "total_partitions": 4,
            },
        }

        # Save schema file
        schema_file = self.catalog_path / "geojson_schema.json"
        with open(schema_file, "w") as f:
            json.dump(geojson_schema, f, indent=2)

        # Test spatial resolution
        resolver = spatial_resolver(str(schema_file), str(self.catalog_path))

        # Verify GeoJSON resolver initialization
        assert resolver.grid_system == "geojson"
        assert resolver.global_enabled is False

        # Query area that overlaps with tile_001
        query_area = box(-122.4, 37.75, -122.1, 37.95)
        partitions = resolver.resolve_partitions(query_area)

        assert "tile_001" in partitions, "Should resolve tile_001 for the query area"
        assert "global" not in partitions, "Global partition should be disabled"

        # Test query path generation for GeoJSON tiles (create mock directory)
        tile_dir = self.catalog_path / "tile_001"
        tile_dir.mkdir(exist_ok=True)

        query_paths = resolver.generate_query_paths(["tile_001"], "2024-*")
        assert isinstance(query_paths, list), "Should return list of query paths"
        if len(query_paths) > 0:
            assert any("tile_001" in path for path in query_paths), "Query path should include resolved tile"

    def test_schema_validation_and_error_handling(self):
        """Test schema validation and error handling in integration scenarios."""

        # Test with invalid schema
        invalid_schema = {"spatial_partitioning": {"grid_system": "invalid_grid"}}  # Invalid grid system

        schema_file = self.catalog_path / "invalid_schema.json"
        with open(schema_file, "w") as f:
            json.dump(invalid_schema, f)

        # Should raise error for invalid grid system
        with pytest.raises(ValueError, match="Unsupported grid system"):
            resolver = spatial_resolver(str(schema_file), str(self.catalog_path))
            resolver.resolve_partitions(box(-122.5, 37.7, -122.0, 38.0))

        # Test with missing schema file
        with pytest.raises(FileNotFoundError):
            spatial_resolver("/nonexistent/schema.json", str(self.catalog_path))


if __name__ == "__main__":
    # Allow running tests directly
    pytest.main([__file__])
