"""
Claude Agent SDK Adapter - Wrapper for the Claude Agent SDK.

This adapter provides a unified interface for using the Claude Agent SDK
(which is essentially "Claude Code as a library") for programmatic automation.

The Claude Agent SDK bundles the same capabilities as Claude Code CLI but
accessible via Python API, making it ideal for automation pipelines.

Usage:
    from agent_orchestrator.adapters.claude_sdk import ClaudeSDKAdapter

    adapter = ClaudeSDKAdapter(
        agent_id="claude-main",
        api_key=os.environ["ANTHROPIC_API_KEY"],
    )
    response = await adapter.execute("Implement user authentication", context)
"""

import asyncio
from dataclasses import dataclass
from datetime import datetime
from typing import Any, AsyncIterator, Optional

from .base import (
    LLMAdapter,
    AgentResponse,
    AgentStatus,
    UsageStats,
    PromptBuilder,
)
from .pricing import estimate_cost
from ..journal.status_packet import (
    StatusPacket,
    TaskArtifacts,
    create_success_packet,
    create_failed_packet,
)
from ..secrets.redactor import SecretRedactor


@dataclass
class ClaudeSDKConfig:
    """Configuration for Claude SDK adapter."""

    api_key: str
    model: str = "claude-sonnet-4-20250514"
    max_tokens: int = 8192
    temperature: float = 0.7
    timeout_seconds: int = 300


class ClaudeSDKAdapter(LLMAdapter):
    """
    Adapter for the Claude Agent SDK.

    Provides programmatic access to Claude's agentic capabilities,
    suitable for automation and pipeline integration.

    Note: Requires the claude-agent-sdk package to be installed:
        pip install claude-agent-sdk
    """

    def __init__(
        self,
        agent_id: str,
        api_key: str,
        model: str = "claude-sonnet-4-20250514",
        config: Optional[ClaudeSDKConfig] = None,
    ) -> None:
        """
        Initialize the Claude SDK adapter.

        Args:
            agent_id: Unique identifier for this agent instance
            api_key: Anthropic API key
            model: Model to use (default: claude-sonnet-4-20250514)
            config: Optional full configuration
        """
        super().__init__(agent_id, model)
        self.api_key = api_key
        self.config = config or ClaudeSDKConfig(api_key=api_key, model=model)
        self._client = None
        self._last_packet: Optional[StatusPacket] = None

    def _get_client(self):
        """Get or create the SDK client."""
        if self._client is None:
            try:
                # Try to import the Claude Agent SDK
                from claude_agent_sdk import ClaudeSDKClient

                self._client = ClaudeSDKClient(api_key=self.api_key)
            except ImportError:
                # Fall back to direct Anthropic API if SDK not available
                try:
                    import anthropic

                    self._client = anthropic.Anthropic(api_key=self.api_key)
                except ImportError:
                    raise ImportError(
                        "Neither claude-agent-sdk nor anthropic package is installed. "
                        "Install with: pip install claude-agent-sdk or pip install anthropic"
                    )
        return self._client

    async def execute(self, task: str, context: dict[str, Any]) -> AgentResponse:
        """
        Execute a task using the Claude SDK.

        Args:
            task: The task description/prompt
            context: Additional context including project state

        Returns:
            AgentResponse with result and usage metrics
        """
        self._status = AgentStatus.RUNNING
        start_time = datetime.now()

        try:
            client = self._get_client()

            # Build the prompt with context
            prompt = self._build_prompt(task, context)

            # Check if we're using the SDK or direct API
            if hasattr(client, "query"):
                # Using Claude Agent SDK
                response = await self._execute_with_sdk(client, prompt)
            else:
                # Using direct Anthropic API
                response = await self._execute_with_api(client, prompt)

            # Update usage stats
            self._usage_stats.add_response(response)

            # Create status packet
            self._last_packet = create_success_packet(
                agent_id=self.agent_id,
                task_id=self._current_task_id or "",
                summary=f"Completed: {task[:100]}...",
                files_modified=response.artifacts.files_modified,
                next_steps=["Review output", "Run tests"],
            )
            self._last_packet.artifacts = response.artifacts

            self._status = AgentStatus.IDLE
            return response

        except Exception as e:
            error_msg = SecretRedactor.redact(str(e))
            self._last_packet = create_failed_packet(
                agent_id=self.agent_id,
                task_id=self._current_task_id or "",
                error_message=error_msg,
            )
            self._status = AgentStatus.IDLE
            self._usage_stats.errors_count += 1

            return AgentResponse(
                content="",
                success=False,
                error=error_msg,
            )

    async def _execute_with_sdk(self, client, prompt: str) -> AgentResponse:
        """Execute using the Claude Agent SDK."""
        # The SDK provides agentic capabilities
        result = await asyncio.to_thread(
            client.query, prompt
        )

        # Extract usage from SDK response
        usage = getattr(result, "usage", {})
        tokens_input = getattr(usage, "input_tokens", 0)
        tokens_output = getattr(usage, "output_tokens", 0)

        return AgentResponse(
            content=str(result.content) if hasattr(result, "content") else str(result),
            tokens_input=tokens_input,
            tokens_output=tokens_output,
            tokens_used=tokens_input + tokens_output,
            cost=self._estimate_cost(tokens_input, tokens_output),
            model=self.model,
            artifacts=TaskArtifacts(
                tokens_input=tokens_input,
                tokens_output=tokens_output,
            ),
            success=True,
        )

    async def _execute_with_api(self, client, prompt: str) -> AgentResponse:
        """Execute using the direct Anthropic API."""
        # Run in thread pool since anthropic client is sync
        response = await asyncio.to_thread(
            client.messages.create,
            model=self.config.model,
            max_tokens=self.config.max_tokens,
            messages=[{"role": "user", "content": prompt}],
        )

        # Extract content
        content = ""
        if response.content:
            content = response.content[0].text if response.content else ""

        # Extract usage
        tokens_input = response.usage.input_tokens
        tokens_output = response.usage.output_tokens

        return AgentResponse(
            content=content,
            tokens_input=tokens_input,
            tokens_output=tokens_output,
            tokens_used=tokens_input + tokens_output,
            cost=self._estimate_cost(tokens_input, tokens_output),
            model=response.model,
            artifacts=TaskArtifacts(
                tokens_input=tokens_input,
                tokens_output=tokens_output,
            ),
            success=True,
        )

    async def stream(self, task: str, context: dict[str, Any]) -> AsyncIterator[str]:
        """
        Stream response for real-time output.

        Args:
            task: The task description
            context: Additional context

        Yields:
            Response chunks as they become available
        """
        self._status = AgentStatus.RUNNING

        try:
            client = self._get_client()
            prompt = self._build_prompt(task, context)

            # Use streaming API
            if hasattr(client, "messages"):
                # Direct Anthropic API with streaming
                with client.messages.stream(
                    model=self.config.model,
                    max_tokens=self.config.max_tokens,
                    messages=[{"role": "user", "content": prompt}],
                ) as stream:
                    for text in stream.text_stream:
                        yield text

            else:
                # Fall back to non-streaming
                response = await self.execute(task, context)
                yield response.content

        except Exception as e:
            yield f"Error: {SecretRedactor.redact(str(e))}"

        finally:
            self._status = AgentStatus.IDLE

    def _build_prompt(self, task: str, context: dict[str, Any]) -> str:
        """Build the full prompt with context."""
        builder = PromptBuilder.for_api_agent()
        return builder.build(
            task,
            context,
            output_requirements=PromptBuilder.minimal_output_requirements(),
        )

    def _estimate_cost(self, tokens_input: int, tokens_output: int) -> float:
        """Estimate cost based on token usage."""
        return estimate_cost(self.model, tokens_input, tokens_output, provider="anthropic")

    def write_status_packet(self) -> StatusPacket:
        """Return the last status packet."""
        if self._last_packet:
            return self._last_packet

        return StatusPacket(
            agent_id=self.agent_id,
            task_id=self._current_task_id or "",
            status="idle",
            artifacts=TaskArtifacts(
                tokens_input=self._usage_stats.tokens_input,
                tokens_output=self._usage_stats.tokens_output,
                cost_usd=self._usage_stats.total_cost,
            ),
        )

    def is_healthy(self) -> bool:
        """Check if the adapter can connect to the API."""
        try:
            # Simple health check - verify API key format
            if not self.api_key or not self.api_key.startswith("sk-ant-"):
                return False
            return True
        except Exception:
            return False

    def get_name(self) -> str:
        """Get adapter name."""
        return f"ClaudeSDK({self.model})"
