"""Tests for the Cloudy runtime."""

from __future__ import annotations

import pytest

from presentations_ai import AuthenticationError, CloudyError
from presentations_ai.cloudy._system_prompt import CLOUDY_SYSTEM_PROMPT
from presentations_ai.cloudy.runtime import _extract_presentation_details
from presentations_ai.cloudy.types import CloudyToolCall


class TestCloudyRuntimeConstructor:
    def test_requires_anthropic_api_key(self) -> None:
        with pytest.raises(AuthenticationError, match="anthropic_api_key is required"):
            from presentations_ai.cloudy import CloudyRuntime

            CloudyRuntime(anthropic_api_key="")

    def test_requires_anthropic_package(self, monkeypatch: pytest.MonkeyPatch) -> None:
        """Should raise ImportError if anthropic is not installed."""
        import builtins

        original_import = builtins.__import__

        def mock_import(name: str, *args: object, **kwargs: object) -> object:
            if name == "anthropic":
                raise ImportError("No module named 'anthropic'")
            return original_import(name, *args, **kwargs)

        monkeypatch.setattr(builtins, "__import__", mock_import)

        with pytest.raises(ImportError, match="pip install presentations-ai\\[cloudy\\]"):
            from presentations_ai.cloudy.runtime import CloudyRuntime

            CloudyRuntime(anthropic_api_key="sk-ant-test")


class TestExtractPresentationDetails:
    def test_extracts_url_from_access_pattern(self) -> None:
        calls = [
            CloudyToolCall(
                tool_name="create_presentation_topic",
                server_name="presentations-ai",
                input={},
                result="**Access:** https://app.presentations.ai/view/abc123\n**Document ID:** 42",
            )
        ]
        result = _extract_presentation_details(calls)
        assert result["presentation_url"] == "https://app.presentations.ai/view/abc123"
        assert result["document_id"] == 42

    def test_extracts_url_from_document_url_pattern(self) -> None:
        calls = [
            CloudyToolCall(
                tool_name="check_job_status",
                server_name="presentations-ai",
                input={},
                result=(
                    "**Document URL:** https://app.presentations.ai/view/def456"
                    "\n**Document ID:** 99"
                ),
            )
        ]
        result = _extract_presentation_details(calls)
        assert result["presentation_url"] == "https://app.presentations.ai/view/def456"
        assert result["document_id"] == 99

    def test_extracts_animated_url(self) -> None:
        calls = [
            CloudyToolCall(
                tool_name="test",
                server_name="presentations-ai",
                input={},
                result="**Access:** https://x.com/view\n**Animated:** https://x.com/animated",
            )
        ]
        result = _extract_presentation_details(calls)
        assert result["animated_url"] == "https://x.com/animated"

    def test_extracts_animated_url_alternate_pattern(self) -> None:
        calls = [
            CloudyToolCall(
                tool_name="test",
                server_name="presentations-ai",
                input={},
                result="**Access:** https://x.com/view\n**Animated URL:** https://x.com/anim2",
            )
        ]
        result = _extract_presentation_details(calls)
        assert result["animated_url"] == "https://x.com/anim2"

    def test_extracts_job_id(self) -> None:
        calls = [
            CloudyToolCall(
                tool_name="test",
                server_name="presentations-ai",
                input={},
                result="**Job ID:** job_xyz789",
            )
        ]
        result = _extract_presentation_details(calls)
        assert result["job_id"] == "job_xyz789"

    def test_skips_error_calls(self) -> None:
        calls = [
            CloudyToolCall(
                tool_name="test",
                server_name="presentations-ai",
                input={},
                result="**Access:** https://bad.com\n**Document ID:** 1",
                is_error=True,
            ),
            CloudyToolCall(
                tool_name="test",
                server_name="presentations-ai",
                input={},
                result="**Access:** https://good.com\n**Document ID:** 2",
                is_error=False,
            ),
        ]
        result = _extract_presentation_details(calls)
        assert result["presentation_url"] == "https://good.com"
        assert result["document_id"] == 2

    def test_returns_empty_when_no_matches(self) -> None:
        calls = [
            CloudyToolCall(
                tool_name="test",
                server_name="presentations-ai",
                input={},
                result="Some random text without patterns",
            )
        ]
        result = _extract_presentation_details(calls)
        assert result == {}

    def test_returns_empty_for_empty_calls(self) -> None:
        assert _extract_presentation_details([]) == {}


class TestSystemPrompt:
    def test_system_prompt_is_non_empty(self) -> None:
        assert len(CLOUDY_SYSTEM_PROMPT) > 100

    def test_system_prompt_mentions_key_tools(self) -> None:
        assert "create_presentation_topic" in CLOUDY_SYSTEM_PROMPT
        assert "create_single_slide" in CLOUDY_SYSTEM_PROMPT
        assert "check_job_status" in CLOUDY_SYSTEM_PROMPT
        assert "update_document_content" in CLOUDY_SYSTEM_PROMPT

    def test_system_prompt_mentions_preservation_modes(self) -> None:
        assert "enhance" in CLOUDY_SYSTEM_PROMPT
        assert "preserve" in CLOUDY_SYSTEM_PROMPT
        assert "summarize" in CLOUDY_SYSTEM_PROMPT
        assert "instruction" in CLOUDY_SYSTEM_PROMPT

    def test_system_prompt_mentions_error_handling(self) -> None:
        assert "out of credits" in CLOUDY_SYSTEM_PROMPT
        assert "Rate limited" in CLOUDY_SYSTEM_PROMPT


class TestCloudyRuntimeChatValidation:
    """Test chat() input validation without requiring anthropic SDK."""

    def _make_runtime_with_mock(self) -> object:
        """Create a runtime with a mocked anthropic client."""
        try:
            from presentations_ai.cloudy import CloudyRuntime

            runtime = CloudyRuntime(anthropic_api_key="sk-ant-test-key")
            return runtime
        except ImportError:
            pytest.skip("anthropic package not installed")

    def test_chat_rejects_empty_message(self) -> None:
        runtime = self._make_runtime_with_mock()
        if runtime is None:
            return
        with pytest.raises(CloudyError, match="user_message must be a non-empty string"):
            runtime.chat("", "pai_key")  # type: ignore[union-attr]

    def test_chat_rejects_empty_api_key(self) -> None:
        runtime = self._make_runtime_with_mock()
        if runtime is None:
            return
        with pytest.raises(
            AuthenticationError,
            match="presentationsApiKey is required|presentations_api_key",
        ):
            runtime.chat("Create a deck", "")  # type: ignore[union-attr]
