"""InvokeClaudeCodeService - Send prompts to Claude Code subprocess.

Contract: CNT-T2-SVC-002
Traceability: UC-002
"""

from collections.abc import Iterator
from pathlib import Path

from laida_cli.ports.claude_code_port import ClaudeCodeError, ClaudeCodePort


class InvokeClaudeCodeService:
    """Service for invoking Claude Code with prompts.

    Provides both blocking and streaming execution modes.
    Use invoke() for simple cases, invoke_streaming() for real-time feedback.
    """

    DEFAULT_TIMEOUT = 300  # 5 minutes

    def __init__(self, claude_port: ClaudeCodePort) -> None:
        """Initialize with Claude Code port.

        Args:
            claude_port: Port for Claude Code interaction
        """
        self._claude_port = claude_port

    def invoke(
        self,
        prompt: str,
        working_dir: Path,
        timeout_seconds: int = DEFAULT_TIMEOUT,  # noqa: ARG002
    ) -> str:
        """Send prompt to Claude Code and get response.

        Blocks until execution completes. For real-time output,
        use invoke_streaming() instead.

        Args:
            prompt: The prompt to send
            working_dir: Working directory for execution
            timeout_seconds: Maximum execution time

        Returns:
            Claude Code response (stdout)

        Raises:
            ClaudeCodeError: If invocation fails
        """
        self._validate_inputs(prompt, working_dir)
        return self._claude_port.send_prompt(prompt, working_dir)

    def invoke_streaming(
        self,
        prompt: str,
        working_dir: Path,
    ) -> Iterator[str]:
        """Stream prompt execution with real-time output.

        Yields output lines as they become available, enabling
        responsive UI feedback during long-running executions.

        Args:
            prompt: The prompt to send
            working_dir: Working directory for execution

        Yields:
            Lines of output as they arrive

        Raises:
            ClaudeCodeError: If invocation fails
        """
        self._validate_inputs(prompt, working_dir)
        yield from self._claude_port.stream_prompt(prompt, working_dir)

    def _validate_inputs(self, prompt: str, working_dir: Path) -> None:
        """Validate prompt and working directory.

        Args:
            prompt: The prompt to validate
            working_dir: The directory to validate

        Raises:
            ClaudeCodeError: If validation fails
        """
        if not prompt.strip():
            raise ClaudeCodeError("Prompt cannot be empty")

        if not working_dir.exists():
            raise ClaudeCodeError(f"Working directory does not exist: {working_dir}")
