"""Context compaction for reducing agent memory usage.

Compaction process:
1. Request summary from agent of completed work, patterns, and decisions
2. Replace conversation history with concise summary
3. Measure and validate context reduction achieved

Target: 40-50% context reduction when triggered at 80% threshold.
"""

import logging
from dataclasses import dataclass
from typing import Any

logger = logging.getLogger(__name__)


@dataclass
class CompactionResult:
    """Result of context compaction operation.

    Attributes:
        agent_id: Unique identifier for the agent
        before_tokens: Token count before compaction
        after_tokens: Token count after compaction
        before_percent: Usage percentage before compaction
        after_percent: Usage percentage after compaction
        tokens_freed: Number of tokens freed by compaction
        reduction_percent: Percentage of context freed
        success: Whether compaction succeeded
        error_message: Error message if compaction failed
    """

    agent_id: str
    before_tokens: int
    after_tokens: int
    before_percent: float
    after_percent: float
    tokens_freed: int
    reduction_percent: float
    success: bool
    error_message: str = ""

    def __repr__(self) -> str:
        """String representation."""
        status = "success" if self.success else "failed"
        return (
            f"CompactionResult(agent_id={self.agent_id!r}, "
            f"reduction={self.reduction_percent:.1f}%, "
            f"status={status})"
        )


@dataclass
class SessionRotation:
    """Result of session rotation operation.

    Attributes:
        old_agent_id: Identifier of the closed agent session
        new_agent_id: Identifier of the newly spawned agent
        agent_type: Type of agent (sonnet, haiku, opus, glm)
        next_issue_number: Issue number transferred to new agent
        context_before_tokens: Token count before rotation
        context_before_percent: Usage percentage before rotation
        success: Whether rotation succeeded
        error_message: Error message if rotation failed
    """

    old_agent_id: str
    new_agent_id: str
    agent_type: str
    next_issue_number: int
    context_before_tokens: int
    context_before_percent: float
    success: bool
    error_message: str = ""

    def __repr__(self) -> str:
        """String representation."""
        status = "success" if self.success else "failed"
        return (
            f"SessionRotation(old={self.old_agent_id!r}, "
            f"new={self.new_agent_id!r}, "
            f"issue=#{self.next_issue_number}, "
            f"status={status})"
        )


class ContextCompactor:
    """Handles context compaction to free agent memory.

    Compaction is triggered when an agent reaches 80% context usage.
    The compactor requests a summary from the agent and replaces the
    conversation history with a concise summary, freeing memory.
    """

    SUMMARY_PROMPT = """Please provide a concise summary of your completed work so far.

Focus on:
- Key tasks completed
- Important patterns or approaches discovered
- Critical decisions made and rationale
- Any findings that future work should be aware of

Keep the summary concise but informative. This will replace the detailed conversation history."""

    def __init__(self, api_client: Any) -> None:
        """Initialize context compactor.

        Args:
            api_client: Claude API client for compaction operations
        """
        self.api_client = api_client

    async def request_summary(self, agent_id: str) -> str:
        """Request agent to summarize completed work.

        Args:
            agent_id: Unique identifier for the agent

        Returns:
            Summary text from agent

        Raises:
            Exception: If API call fails
        """
        logger.info(f"Requesting work summary from agent {agent_id}")

        response = await self.api_client.send_message(agent_id, self.SUMMARY_PROMPT)
        summary: str = response["content"]

        logger.debug(f"Received summary from {agent_id}: {len(summary)} characters")
        return summary

    async def compact(self, agent_id: str) -> CompactionResult:
        """Compact agent's context by replacing history with summary.

        Args:
            agent_id: Unique identifier for the agent

        Returns:
            CompactionResult with before/after metrics
        """
        logger.info(f"Starting context compaction for agent {agent_id}")

        try:
            # Get context usage before compaction
            before_usage = await self.api_client.get_context_usage(agent_id)
            before_tokens = before_usage["used_tokens"]
            before_total = before_usage["total_tokens"]
            before_percent = (before_tokens / before_total * 100) if before_total > 0 else 0

            logger.info(
                f"Agent {agent_id} context before compaction: "
                f"{before_tokens}/{before_total} ({before_percent:.1f}%)"
            )

            # Request summary from agent
            summary = await self.request_summary(agent_id)

            # Replace conversation history with summary
            await self.api_client.replace_history(agent_id, summary)

            # Get context usage after compaction
            after_usage = await self.api_client.get_context_usage(agent_id)
            after_tokens = after_usage["used_tokens"]
            after_total = after_usage["total_tokens"]
            after_percent = (after_tokens / after_total * 100) if after_total > 0 else 0

            # Calculate reduction metrics
            tokens_freed = before_tokens - after_tokens
            reduction_percent = (
                (tokens_freed / before_tokens * 100) if before_tokens > 0 else 0
            )

            logger.info(
                f"Agent {agent_id} context after compaction: "
                f"{after_tokens}/{after_total} ({after_percent:.1f}%), "
                f"freed {tokens_freed} tokens ({reduction_percent:.1f}% reduction)"
            )

            return CompactionResult(
                agent_id=agent_id,
                before_tokens=before_tokens,
                after_tokens=after_tokens,
                before_percent=before_percent,
                after_percent=after_percent,
                tokens_freed=tokens_freed,
                reduction_percent=reduction_percent,
                success=True,
            )

        except Exception as e:
            logger.error(f"Compaction failed for agent {agent_id}: {e}")
            return CompactionResult(
                agent_id=agent_id,
                before_tokens=0,
                after_tokens=0,
                before_percent=0.0,
                after_percent=0.0,
                tokens_freed=0,
                reduction_percent=0.0,
                success=False,
                error_message=str(e),
            )
