"""Example plugin: Anthropic API direct integration (without Claude SDK).

This demonstrates a complete working plugin implementation using the
Anthropic API directly via HTTP requests.

Installation:
    1. Copy to ~/.cleave/backends/anthropic_legacy.py
    2. Set ANTHROPIC_API_KEY environment variable
    3. Configure in cleave:
       cleave config set backend anthropic-legacy
       cleave config set backends.anthropic-legacy.model claude-sonnet-4-5-20250929
    4. Run TUI:
       cleave tui

Requirements:
    pip install httpx  # Or install cleave with [local] extras
"""

import json
import os
from collections.abc import AsyncIterator

import httpx

from cleave.tui.backends.base import (
    Backend,
    BackendConfig,
    BackendConnectionError,
    BackendState,
    Message,
    MessageType,
)


class AnthropicLegacyBackend(Backend):
    """Direct Anthropic API integration without Claude SDK.

    This backend uses the Anthropic Messages API to interact with
    Claude models. It demonstrates streaming support and proper
    error handling.
    """

    API_URL = "https://api.anthropic.com/v1/messages"
    API_VERSION = "2023-06-01"

    def __init__(self):
        """Initialize backend state."""
        self._state = BackendState.DISCONNECTED
        self._error: str | None = None
        self._config: BackendConfig | None = None
        self._client: httpx.AsyncClient | None = None
        self._api_key: str | None = None

    @property
    def name(self) -> str:
        """Backend display name."""
        return "Anthropic (Direct API)"

    @property
    def state(self) -> BackendState:
        """Current connection state."""
        return self._state

    @property
    def error(self) -> str | None:
        """Last error message."""
        return self._error

    async def connect(self, config: BackendConfig) -> None:
        """Establish connection to Anthropic API.

        Args:
            config: Backend configuration.

        Raises:
            BackendConnectionError: If API key is missing or connection fails.
        """
        self._state = BackendState.CONNECTING
        self._config = config

        # Get API key
        self._api_key = config.api_key or os.getenv("ANTHROPIC_API_KEY")
        if not self._api_key:
            self._state = BackendState.ERROR
            self._error = "Missing ANTHROPIC_API_KEY"
            raise BackendConnectionError("ANTHROPIC_API_KEY not set")

        # Create HTTP client
        try:
            self._client = httpx.AsyncClient(
                timeout=config.timeout,
                headers={
                    "anthropic-version": self.API_VERSION,
                    "x-api-key": self._api_key,
                    "content-type": "application/json",
                },
            )

            # Test connection
            response = await self._client.get(
                "https://api.anthropic.com/v1/messages",
                headers={"anthropic-version": self.API_VERSION},
            )

            if response.status_code == 401:
                raise BackendConnectionError("Invalid API key")

            self._state = BackendState.CONNECTED
            self._error = None

        except Exception as e:
            self._state = BackendState.ERROR
            self._error = str(e)
            raise BackendConnectionError(f"Connection failed: {e}") from e

    async def disconnect(self) -> None:
        """Close HTTP client."""
        if self._client:
            await self._client.aclose()
            self._client = None

        self._state = BackendState.DISCONNECTED
        self._error = None

    async def query(self, prompt: str) -> AsyncIterator[Message]:
        """Send prompt to Anthropic API with streaming.

        Args:
            prompt: User message.

        Yields:
            Streaming messages (STREAM_START, STREAM_DELTA, STREAM_END).

        Raises:
            RuntimeError: If not connected.
        """
        if self._state != BackendState.CONNECTED or not self._client:
            raise RuntimeError("Not connected")

        # Build request payload
        payload = {
            "model": self._config.model or "claude-sonnet-4-5-20250929",
            "max_tokens": 4096,
            "messages": [{"role": "user", "content": prompt}],
            "stream": True,
        }

        if self._config.system_prompt:
            payload["system"] = self._config.system_prompt

        try:
            # Signal stream start
            yield Message(
                role="assistant",
                content="",
                message_type=MessageType.STREAM_START,
            )

            full_response = ""

            # Stream response
            async with self._client.stream(
                "POST",
                self.API_URL,
                json=payload,
            ) as response:
                response.raise_for_status()

                async for line in response.aiter_lines():
                    if not line.strip() or not line.startswith("data: "):
                        continue

                    data_str = line[6:]  # Remove "data: " prefix

                    if data_str == "[DONE]":
                        break

                    try:
                        data = json.loads(data_str)
                    except json.JSONDecodeError:
                        continue

                    # Handle different event types
                    event_type = data.get("type")

                    if event_type == "content_block_delta":
                        delta = data.get("delta", {})
                        if delta.get("type") == "text_delta":
                            text = delta.get("text", "")
                            full_response += text

                            yield Message(
                                role="assistant",
                                content=text,
                                message_type=MessageType.STREAM_DELTA,
                            )

                    elif event_type == "message_stop":
                        break

            # Signal stream end
            yield Message(
                role="assistant",
                content=full_response,
                message_type=MessageType.STREAM_END,
            )

        except httpx.HTTPStatusError as e:
            self._state = BackendState.ERROR
            self._error = f"API error: {e.response.status_code}"
            yield Message(
                role="assistant",
                content=f"API error {e.response.status_code}: {e.response.text}",
                metadata={"error": True},
            )

        except Exception as e:
            self._state = BackendState.ERROR
            self._error = str(e)
            yield Message(
                role="assistant",
                content=f"Error: {e}",
                metadata={"error": True},
            )

    @classmethod
    def check_auth(cls) -> tuple[bool, str]:
        """Check if ANTHROPIC_API_KEY is set.

        Returns:
            Tuple of (is_authenticated, status_message).
        """
        api_key = os.getenv("ANTHROPIC_API_KEY")
        if api_key:
            return (True, "ANTHROPIC_API_KEY configured")
        return (False, "Set ANTHROPIC_API_KEY environment variable")

    @classmethod
    def available_models(cls, config: BackendConfig | None = None) -> list[str]:
        """List available Claude models.

        Returns:
            List of Claude model identifiers.
        """
        return [
            "claude-sonnet-4-5-20250929",
            "claude-opus-4-5-20251101",
            "claude-3-7-sonnet-20250219",
            "claude-3-5-haiku-20241022",
            "claude-3-opus-20240229",
        ]

    @classmethod
    def default_config(cls) -> BackendConfig:
        """Get default configuration.

        Returns:
            BackendConfig with Claude defaults.
        """
        return BackendConfig(
            model="claude-sonnet-4-5-20250929",
            timeout=120.0,
            max_turns=50,
            system_prompt="You are a helpful AI assistant.",
        )


# Plugin metadata
__plugin_name__ = "anthropic-legacy"
__plugin_version__ = "1.0.0"
__plugin_author__ = "Cleave Team"
__plugin_backend__ = AnthropicLegacyBackend
__plugin_description__ = "Direct Anthropic API integration (no SDK required)"
