"""Integration tests that hit the real AIR backend.

These are skipped automatically when AIR_API_KEY is not set.

Run them with::

    export AIR_API_KEY="air_k1_..."
    export AIR_BASE_URL="http://localhost:8000"   # optional
    pytest tests/test_integration.py -v
"""

import os
import uuid

import pytest

from air import AIR, AIRError, AuthError, Project

# ---------------------------------------------------------------------------
# Skip the entire module when credentials are missing
# ---------------------------------------------------------------------------

API_KEY = os.environ.get("AIR_API_KEY")
BASE_URL = os.environ.get("AIR_BASE_URL", "http://localhost:8000")

pytestmark = pytest.mark.skipif(
    not API_KEY,
    reason="AIR_API_KEY not set — skipping integration tests",
)


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------

@pytest.fixture(scope="module")
def client():
    """A shared AIR client for the entire test module."""
    c = AIR(api_key=API_KEY, base_url=BASE_URL)
    yield c
    c.close()


@pytest.fixture()
def project_name():
    """Generate a unique project name for each test."""
    return f"sdk-test-{uuid.uuid4().hex[:8]}"


# ---------------------------------------------------------------------------
# Health
# ---------------------------------------------------------------------------

class TestHealth:
    def test_health(self, client):
        result = client.health()
        assert isinstance(result, dict)
        assert "status" in result


# ---------------------------------------------------------------------------
# Auth
# ---------------------------------------------------------------------------

class TestAuth:
    def test_bad_api_key(self):
        """A fabricated key should fail at some point (auth or request)."""
        bad_client = AIR(api_key="air_k1_invalid", base_url=BASE_URL)
        try:
            bad_client.keywords("test")
            # If the backend doesn't enforce auth, the call may succeed —
            # that's fine for this test; we just verify no crash.
        except (AuthError, AIRError):
            pass  # expected
        finally:
            bad_client.close()


# ---------------------------------------------------------------------------
# Keywords
# ---------------------------------------------------------------------------

class TestKeywords:
    def test_keywords_unesco(self, client):
        result = client.keywords(
            "We study the cosmic microwave background and gravitational lensing.",
            n=3,
            kw_type="unesco",
        )
        assert isinstance(result, list)
        assert len(result) > 0

    def test_keywords_aas(self, client):
        result = client.keywords(
            "Dark matter halos and galaxy clustering in cosmological simulations.",
            n=5,
            kw_type="aas",
        )
        # AAS keywords return a dict (keyword -> URI), not a list.
        assert isinstance(result, (list, dict))
        assert len(result) > 0


# ---------------------------------------------------------------------------
# Project lifecycle
# ---------------------------------------------------------------------------

class TestProjectLifecycle:
    def test_create_list_get_delete(self, client, project_name):
        # Create
        project = client.create_project(
            project_name,
            data_description="Integration test project.",
        )
        assert isinstance(project, Project)
        assert project.name == project_name

        try:
            # List — our project should be present
            projects = client.list_projects()
            assert isinstance(projects, list)
            assert project_name in projects

            # Get
            same_project = client.get_project(project_name)
            assert same_project.name == project_name
        finally:
            # Delete (cleanup even if assertions fail)
            project.delete()

        # Verify deletion — project should no longer appear in the list
        projects_after = client.list_projects()
        assert project_name not in projects_after


# ---------------------------------------------------------------------------
# Project files
# ---------------------------------------------------------------------------

class TestProjectFiles:
    def test_write_and_read_file(self, client, project_name):
        project = client.create_project(project_name)
        try:
            # Write
            project.write_file("test.txt", "hello from SDK integration test")

            # Read back
            content = project.get_file("test.txt")
            assert content == "hello from SDK integration test"

            # List files — should include our file
            files = project.list_files()
            assert isinstance(files, list)
            paths = [f.get("relative_path", f.get("path", "")) for f in files]
            assert any("test.txt" in p for p in paths)
        finally:
            project.delete()


# ---------------------------------------------------------------------------
# Idea generation (slow — marked separately)
# ---------------------------------------------------------------------------

@pytest.mark.slow
class TestIdea:
    def test_idea_generation(self, client, project_name):
        project = client.create_project(
            project_name,
            data_description="We study cosmic microwave background anisotropies.",
        )
        try:
            idea = project.idea(mode="fast", timeout=900)
            assert isinstance(idea, str)
            assert len(idea) > 0
        finally:
            project.delete()
