"""
API Contract Tests using Schemathesis.

These tests demonstrate Schemathesis contract testing capabilities.
Schemathesis auto-generates test cases from OpenAPI schema and validates
that responses match documented schemas.

Usage:
    make test-e2e-schema   # Run schema tests only
    make test-e2e          # Run all E2E tests

Note: Schemathesis v4.x API - filtering is done via include/exclude methods.
"""

import pytest

try:
    from hypothesis import settings
    from schemathesis import openapi

    SCHEMATHESIS_AVAILABLE = True
except ImportError:
    SCHEMATHESIS_AVAILABLE = False


# Skip all tests in this module if schemathesis is not installed
pytestmark = [
    pytest.mark.e2e,
    pytest.mark.schemathesis,
    pytest.mark.skipif(
        not SCHEMATHESIS_AVAILABLE,
        reason="schemathesis not installed - run: make install-e2e",
    ),
]


if SCHEMATHESIS_AVAILABLE:
    from app.main import app

    # Load schema from the FastAPI app using schemathesis.openapi (v4.x API)
    schema = openapi.from_asgi("/api/v1/openapi.json", app=app)

    # =========================================================================
    # Public Endpoints (No Auth Required)
    # =========================================================================

    # Test root endpoint
    root_schema = schema.include(path="/")

    @root_schema.parametrize()
    @settings(max_examples=5)
    def test_root_endpoint_schema(case):
        """Root endpoint schema compliance."""
        response = case.call()
        assert response.status_code < 500, f"Server error: {response.text}"

    # Test health endpoint
    health_schema = schema.include(path="/health")

    @health_schema.parametrize()
    @settings(max_examples=3)
    def test_health_endpoint_schema(case):
        """Health endpoint schema compliance."""
        response = case.call()
        # Health check may return 200 or 503 depending on DB
        assert response.status_code < 500 or response.status_code == 503

    # Test auth registration endpoint
    auth_register_schema = schema.include(path="/api/v1/auth/register")

    @auth_register_schema.parametrize()
    @settings(max_examples=10)
    def test_register_endpoint_validates_input(case):
        """Registration endpoint input validation."""
        response = case.call()
        # 200/201 (success), 400/422 (validation), 409 (conflict)
        assert response.status_code < 500, f"Server error: {response.text}"

    # Note: Login and refresh endpoints require database, so they're tested
    # in test_database_workflows.py instead of here. Schemathesis tests run
    # without the testcontainers database fixtures.

    # =========================================================================
    # Protected Endpoints - Manual tests for auth requirements
    # (Schemathesis parametrize tests all methods, manual tests are clearer)
    # =========================================================================

    class TestProtectedEndpointsRequireAuth:
        """Test that protected endpoints return proper auth errors."""

        def test_users_me_requires_auth(self):
            """Users/me GET endpoint requires authentication."""
            from starlette.testclient import TestClient

            with TestClient(app) as client:
                response = client.get("/api/v1/users/me")
                assert response.status_code == 401

        def test_sessions_me_requires_auth(self):
            """Sessions/me GET endpoint requires authentication."""
            from starlette.testclient import TestClient

            with TestClient(app) as client:
                response = client.get("/api/v1/sessions/me")
                assert response.status_code == 401

        def test_organizations_me_requires_auth(self):
            """Organizations/me GET endpoint requires authentication."""
            from starlette.testclient import TestClient

            with TestClient(app) as client:
                response = client.get("/api/v1/organizations/me")
                assert response.status_code == 401

        def test_admin_users_requires_auth(self):
            """Admin users GET endpoint requires authentication."""
            from starlette.testclient import TestClient

            with TestClient(app) as client:
                response = client.get("/api/v1/admin/users")
                assert response.status_code == 401

        def test_admin_stats_requires_auth(self):
            """Admin stats GET endpoint requires authentication."""
            from starlette.testclient import TestClient

            with TestClient(app) as client:
                response = client.get("/api/v1/admin/stats")
                assert response.status_code == 401

        def test_admin_organizations_requires_auth(self):
            """Admin organizations GET endpoint requires authentication."""
            from starlette.testclient import TestClient

            with TestClient(app) as client:
                response = client.get("/api/v1/admin/organizations")
                assert response.status_code == 401

    # =========================================================================
    # Schema Validation Tests
    # =========================================================================

    class TestSchemaValidation:
        """Manual validation tests for schema structure."""

        def test_schema_loaded_successfully(self):
            """Verify schema was loaded from the app."""
            ops = list(schema.get_all_operations())
            assert len(ops) > 0, "No operations found in schema"

        def test_multiple_endpoints_documented(self):
            """Verify multiple endpoints are documented in schema."""
            ops = list(schema.get_all_operations())
            assert len(ops) >= 10, f"Only {len(ops)} operations found"

        def test_schema_has_auth_operations(self):
            """Verify auth-related operations exist."""
            auth_ops = list(schema.include(path_regex=r".*auth.*").get_all_operations())
            assert len(auth_ops) > 0, "No auth operations found"

        def test_schema_has_user_operations(self):
            """Verify user-related operations exist."""
            user_ops = list(
                schema.include(path_regex=r".*users.*").get_all_operations()
            )
            assert len(user_ops) > 0, "No user operations found"

        def test_schema_has_organization_operations(self):
            """Verify organization-related operations exist."""
            org_ops = list(
                schema.include(path_regex=r".*organizations.*").get_all_operations()
            )
            assert len(org_ops) > 0, "No organization operations found"

        def test_schema_has_admin_operations(self):
            """Verify admin-related operations exist."""
            admin_ops = list(
                schema.include(path_regex=r".*admin.*").get_all_operations()
            )
            assert len(admin_ops) > 0, "No admin operations found"

        def test_schema_has_session_operations(self):
            """Verify session-related operations exist."""
            session_ops = list(
                schema.include(path_regex=r".*sessions.*").get_all_operations()
            )
            assert len(session_ops) > 0, "No session operations found"

        def test_total_endpoint_count(self):
            """Verify expected number of endpoints are documented."""
            ops = list(schema.get_all_operations())
            # We expect at least 40+ endpoints in this comprehensive API
            assert len(ops) >= 40, f"Only {len(ops)} operations found, expected 40+"
