"""
Integration Tests for EduSearch Seeds API.

These tests require a running PostgreSQL database and test the full
request-response cycle through the FastAPI application.

Run with: pytest tests/test_integration/test_edu_search_seeds_integration.py -v
"""

import pytest
import httpx
import os
import uuid
from typing import Generator

# Test configuration
API_BASE = os.environ.get("TEST_API_BASE", "http://localhost:8082")
SKIP_INTEGRATION = os.environ.get("SKIP_INTEGRATION_TESTS", "false").lower() == "true"

# Check if server is reachable
def _check_server_available():
    """Check if the API server is reachable."""
    if SKIP_INTEGRATION:
        return False
    try:
        with httpx.Client(timeout=2.0) as client:
            client.get(f"{API_BASE}/health")
        return True
    except (httpx.ConnectError, httpx.TimeoutException):
        return False

SERVER_AVAILABLE = _check_server_available()

pytestmark = pytest.mark.skipif(
    not SERVER_AVAILABLE,
    reason=f"Integration tests skipped (server at {API_BASE} not available)"
)


@pytest.fixture
def api_client() -> Generator[httpx.Client, None, None]:
    """Create HTTP client for API calls."""
    with httpx.Client(base_url=API_BASE, timeout=30.0) as client:
        yield client


@pytest.fixture
def async_api_client():
    """Create async HTTP client for API calls."""
    return httpx.AsyncClient(base_url=API_BASE, timeout=30.0)


class TestHealthEndpoint:
    """Basic connectivity tests."""

    def test_api_is_reachable(self, api_client: httpx.Client):
        """Test that the API is reachable."""
        response = api_client.get("/health")
        assert response.status_code == 200


class TestCategoriesIntegration:
    """Integration tests for categories endpoint."""

    def test_list_categories_returns_default_categories(self, api_client: httpx.Client):
        """Test that default categories are returned."""
        response = api_client.get("/v1/edu-search/categories")
        assert response.status_code == 200

        data = response.json()
        assert "categories" in data

        # Check for expected default categories
        category_names = [c["name"] for c in data["categories"]]
        expected = ["federal", "states", "science", "portals"]
        for expected_cat in expected:
            assert expected_cat in category_names, f"Missing category: {expected_cat}"


class TestSeedsWorkflow:
    """Integration tests for complete seeds workflow."""

    @pytest.fixture
    def test_seed_url(self):
        """Generate unique URL for test seed."""
        return f"https://test-seed-{uuid.uuid4().hex[:8]}.de"

    def test_create_read_update_delete_seed(self, api_client: httpx.Client, test_seed_url: str):
        """Test complete CRUD workflow for a seed."""
        # CREATE
        create_response = api_client.post(
            "/v1/edu-search/seeds",
            json={
                "url": test_seed_url,
                "name": "Integration Test Seed",
                "description": "Created by integration test",
                "trust_boost": 0.75,
                "enabled": True
            }
        )
        assert create_response.status_code == 200
        create_data = create_response.json()
        assert create_data["status"] == "created"
        seed_id = create_data["id"]

        try:
            # READ
            get_response = api_client.get(f"/v1/edu-search/seeds/{seed_id}")
            assert get_response.status_code == 200
            seed_data = get_response.json()
            assert seed_data["url"] == test_seed_url
            assert seed_data["name"] == "Integration Test Seed"
            assert seed_data["trust_boost"] == 0.75

            # UPDATE
            update_response = api_client.put(
                f"/v1/edu-search/seeds/{seed_id}",
                json={
                    "name": "Updated Test Seed",
                    "enabled": False
                }
            )
            assert update_response.status_code == 200

            # Verify update
            verify_response = api_client.get(f"/v1/edu-search/seeds/{seed_id}")
            assert verify_response.status_code == 200
            updated_data = verify_response.json()
            assert updated_data["name"] == "Updated Test Seed"
            assert updated_data["enabled"] is False

        finally:
            # DELETE (cleanup)
            delete_response = api_client.delete(f"/v1/edu-search/seeds/{seed_id}")
            assert delete_response.status_code == 200

            # Verify deletion
            verify_delete = api_client.get(f"/v1/edu-search/seeds/{seed_id}")
            assert verify_delete.status_code == 404

    def test_list_seeds_with_filters(self, api_client: httpx.Client, test_seed_url: str):
        """Test listing seeds with various filters."""
        # Create a test seed first
        create_response = api_client.post(
            "/v1/edu-search/seeds",
            json={
                "url": test_seed_url,
                "name": "Filter Test Seed",
                "enabled": True
            }
        )
        assert create_response.status_code == 200
        seed_id = create_response.json()["id"]

        try:
            # List all seeds
            list_response = api_client.get("/v1/edu-search/seeds")
            assert list_response.status_code == 200
            assert "seeds" in list_response.json()
            assert "total" in list_response.json()

            # List with enabled filter
            enabled_response = api_client.get("/v1/edu-search/seeds?enabled=true")
            assert enabled_response.status_code == 200

            # List with pagination
            paginated_response = api_client.get("/v1/edu-search/seeds?limit=10&offset=0")
            assert paginated_response.status_code == 200
            assert paginated_response.json()["limit"] == 10

        finally:
            api_client.delete(f"/v1/edu-search/seeds/{seed_id}")

    def test_duplicate_url_rejected(self, api_client: httpx.Client, test_seed_url: str):
        """Test that duplicate URLs are rejected."""
        # Create first seed
        first_response = api_client.post(
            "/v1/edu-search/seeds",
            json={"url": test_seed_url, "name": "First Seed"}
        )
        assert first_response.status_code == 200
        seed_id = first_response.json()["id"]

        try:
            # Try to create duplicate
            duplicate_response = api_client.post(
                "/v1/edu-search/seeds",
                json={"url": test_seed_url, "name": "Duplicate Seed"}
            )
            assert duplicate_response.status_code == 400
            assert "existiert bereits" in duplicate_response.json()["detail"]

        finally:
            api_client.delete(f"/v1/edu-search/seeds/{seed_id}")


class TestBulkImportIntegration:
    """Integration tests for bulk import functionality."""

    def test_bulk_import_multiple_seeds(self, api_client: httpx.Client):
        """Test importing multiple seeds at once."""
        unique_suffix = uuid.uuid4().hex[:8]
        seeds_to_import = [
            {"url": f"https://bulk-test-1-{unique_suffix}.de", "name": "Bulk Test 1", "category": "federal"},
            {"url": f"https://bulk-test-2-{unique_suffix}.de", "name": "Bulk Test 2", "category": "states"},
            {"url": f"https://bulk-test-3-{unique_suffix}.de", "name": "Bulk Test 3", "category": "science"}
        ]

        response = api_client.post(
            "/v1/edu-search/seeds/bulk-import",
            json={"seeds": seeds_to_import}
        )
        assert response.status_code == 200

        data = response.json()
        assert data["status"] == "imported"
        assert data["imported"] == 3
        assert data["skipped"] == 0

        # Cleanup - find and delete imported seeds
        for seed in seeds_to_import:
            list_response = api_client.get("/v1/edu-search/seeds")
            for s in list_response.json()["seeds"]:
                if s["url"] == seed["url"]:
                    api_client.delete(f"/v1/edu-search/seeds/{s['id']}")

    def test_bulk_import_skips_duplicates(self, api_client: httpx.Client):
        """Test that bulk import skips existing URLs."""
        unique_url = f"https://bulk-dup-test-{uuid.uuid4().hex[:8]}.de"

        # First import
        first_response = api_client.post(
            "/v1/edu-search/seeds/bulk-import",
            json={"seeds": [{"url": unique_url, "name": "First Import"}]}
        )
        assert first_response.status_code == 200
        assert first_response.json()["imported"] == 1

        try:
            # Second import with same URL
            second_response = api_client.post(
                "/v1/edu-search/seeds/bulk-import",
                json={"seeds": [{"url": unique_url, "name": "Duplicate Import"}]}
            )
            assert second_response.status_code == 200
            assert second_response.json()["imported"] == 0
            assert second_response.json()["skipped"] == 1

        finally:
            # Cleanup
            list_response = api_client.get("/v1/edu-search/seeds")
            for s in list_response.json()["seeds"]:
                if s["url"] == unique_url:
                    api_client.delete(f"/v1/edu-search/seeds/{s['id']}")


class TestStatsIntegration:
    """Integration tests for statistics endpoint."""

    def test_get_stats_returns_valid_structure(self, api_client: httpx.Client):
        """Test that stats endpoint returns expected structure."""
        response = api_client.get("/v1/edu-search/stats")
        assert response.status_code == 200

        data = response.json()
        assert "total_seeds" in data
        assert "enabled_seeds" in data
        assert "avg_trust_boost" in data
        assert "seeds_per_category" in data

        # Verify types
        assert isinstance(data["total_seeds"], int)
        assert isinstance(data["enabled_seeds"], int)
        assert isinstance(data["avg_trust_boost"], (int, float))
        assert isinstance(data["seeds_per_category"], dict)


class TestExportForCrawlerIntegration:
    """Integration tests for crawler export endpoint."""

    def test_export_returns_valid_format(self, api_client: httpx.Client):
        """Test that export endpoint returns crawler-compatible format."""
        response = api_client.get("/v1/edu-search/seeds/export/for-crawler")
        assert response.status_code == 200

        data = response.json()
        assert "seeds" in data
        assert "generated_at" in data
        assert "total" in data

        # Verify seed format
        if data["seeds"]:
            seed = data["seeds"][0]
            assert "url" in seed
            assert "name" in seed
            assert "trust_boost" in seed
            assert "crawl_depth" in seed

    def test_export_only_includes_enabled_seeds(self, api_client: httpx.Client):
        """Test that export only includes enabled seeds."""
        unique_url = f"https://export-test-{uuid.uuid4().hex[:8]}.de"

        # Create disabled seed
        create_response = api_client.post(
            "/v1/edu-search/seeds",
            json={"url": unique_url, "name": "Disabled Seed", "enabled": False}
        )
        assert create_response.status_code == 200
        seed_id = create_response.json()["id"]

        try:
            export_response = api_client.get("/v1/edu-search/seeds/export/for-crawler")
            assert export_response.status_code == 200

            # Verify disabled seed is not in export
            exported_urls = [s["url"] for s in export_response.json()["seeds"]]
            assert unique_url not in exported_urls

        finally:
            api_client.delete(f"/v1/edu-search/seeds/{seed_id}")


class TestErrorHandling:
    """Integration tests for error handling."""

    def test_get_nonexistent_seed_returns_404(self, api_client: httpx.Client):
        """Test that getting non-existent seed returns 404."""
        fake_id = str(uuid.uuid4())
        response = api_client.get(f"/v1/edu-search/seeds/{fake_id}")
        assert response.status_code == 404

    def test_invalid_uuid_returns_400(self, api_client: httpx.Client):
        """Test that invalid UUID returns 400."""
        response = api_client.get("/v1/edu-search/seeds/not-a-uuid")
        assert response.status_code == 400

    def test_create_seed_with_missing_required_fields(self, api_client: httpx.Client):
        """Test that missing required fields returns 422."""
        response = api_client.post(
            "/v1/edu-search/seeds",
            json={"name": "Missing URL"}  # url is required
        )
        assert response.status_code == 422

    def test_create_seed_with_invalid_url(self, api_client: httpx.Client):
        """Test that invalid URL format is rejected."""
        response = api_client.post(
            "/v1/edu-search/seeds",
            json={"url": "not-a-valid-url", "name": "Invalid URL"}
        )
        # Should be 422 (validation error) or 400
        assert response.status_code in [400, 422]
