"""ClaudeCodePort - Port for Claude Code CLI interaction.

Contract: CNT-T1-PRT-001
Traceability: UC-001, UC-002, UC-003
"""

from collections.abc import Iterator
from pathlib import Path
from typing import Protocol


class ClaudeCodeError(Exception):
    """Error raised when Claude Code interaction fails."""

    def __init__(self, message: str, exit_code: int | None = None) -> None:
        super().__init__(message)
        self.exit_code = exit_code


class ClaudeCodeAuthError(ClaudeCodeError):
    """Error raised when Claude Code authentication fails.

    This error indicates the user needs to authenticate with Claude Code.
    The CLI should catch this and display login instructions.
    """

    def __init__(self, message: str = "Not authenticated with Claude Code") -> None:
        super().__init__(message, exit_code=1)
        self.login_hint = "Run 'laida login' or 'claude' to authenticate."


class ClaudeCodePort(Protocol):
    """Port interface for Claude Code CLI interaction.

    This protocol defines the contract for interacting with Claude Code.
    Implementations should handle subprocess management, timeout, and
    error handling.
    """

    def send_prompt(self, prompt: str, working_dir: Path) -> str:
        """Send a prompt to Claude Code and return the response.

        Args:
            prompt: The prompt text to send
            working_dir: Working directory for Claude Code execution

        Returns:
            The response from Claude Code (stdout)

        Raises:
            ClaudeCodeError: If execution fails
        """
        ...

    def stream_prompt(self, prompt: str, working_dir: Path) -> Iterator[str]:
        """Stream prompt execution, yielding output lines as they arrive.

        This method enables real-time feedback during long-running executions.
        Each yielded string represents a line of output from Claude Code.

        Args:
            prompt: The prompt text to send
            working_dir: Working directory for Claude Code execution

        Yields:
            Lines of output as they become available

        Raises:
            ClaudeCodeError: If execution fails
        """
        ...

    def send_command(self, command: str) -> bool:
        """Send a command to Claude Code (e.g., /clear).

        Args:
            command: The command to send (e.g., "/clear")

        Returns:
            True if command executed successfully
        """
        ...

    def check_completion(self, expected_files: list[str]) -> bool:
        """Check if expected output files exist.

        Args:
            expected_files: List of file paths or glob patterns

        Returns:
            True if all expected files exist
        """
        ...

    def check_auth(self) -> bool:
        """Check if Claude Code is authenticated.

        Performs a lightweight authentication check without executing
        a full prompt.

        Returns:
            True if authenticated and ready to use

        Raises:
            ClaudeCodeAuthError: If authentication fails
        """
        ...
