"""Input history manager for chat input navigation."""

from collections import deque
from pathlib import Path
from typing import Iterator


class InputHistory:
    """Manages input history with navigation and persistence.

    Provides readline-like navigation with Up/Down arrows.
    Optionally persists history to a file for cross-session recall.

    Usage:
        history = InputHistory(max_size=100)
        history.add("first command")
        history.add("second command")

        # Navigate backwards
        history.previous()  # "second command"
        history.previous()  # "first command"

        # Navigate forwards
        history.next()  # "second command"
        history.next()  # "" (returns to current input)
    """

    def __init__(
        self,
        max_size: int = 500,
        history_file: Path | None = None,
    ) -> None:
        """Initialize input history.

        Args:
            max_size: Maximum number of entries to keep.
            history_file: Optional path for persistence.
        """
        self._max_size = max_size
        self._history_file = history_file
        self._entries: deque[str] = deque(maxlen=max_size)
        self._position: int = -1  # -1 means "at current input"
        self._current_input: str = ""  # Saved current input during navigation

        # Load persisted history
        if history_file and history_file.exists():
            self._load()

    def add(self, entry: str) -> None:
        """Add an entry to history.

        Args:
            entry: Text to add (empty strings are ignored).
        """
        entry = entry.strip()
        if not entry:
            return

        # Don't add duplicates of the last entry
        if self._entries and self._entries[-1] == entry:
            return

        self._entries.append(entry)
        self._position = -1  # Reset navigation position
        self._current_input = ""

        # Persist if configured
        if self._history_file:
            self._save()

    def previous(self, current_input: str = "") -> str:
        """Navigate to previous entry.

        Args:
            current_input: Current input to save when starting navigation.

        Returns:
            Previous history entry, or current input if at oldest.
        """
        if not self._entries:
            return current_input

        # Save current input when starting to navigate
        if self._position == -1:
            self._current_input = current_input

        # Move backwards in history
        if self._position < len(self._entries) - 1:
            self._position += 1

        # Return entry from the end (most recent first)
        index = len(self._entries) - 1 - self._position
        return self._entries[index]

    def next(self) -> str:
        """Navigate to next (more recent) entry.

        Returns:
            Next history entry, or saved current input if at newest.
        """
        if self._position <= 0:
            self._position = -1
            return self._current_input

        self._position -= 1
        index = len(self._entries) - 1 - self._position
        return self._entries[index]

    def reset_position(self) -> None:
        """Reset navigation position to current input."""
        self._position = -1
        self._current_input = ""

    def search(self, prefix: str) -> Iterator[str]:
        """Search history for entries starting with prefix.

        Args:
            prefix: Text to search for.

        Yields:
            Matching entries, most recent first.
        """
        prefix_lower = prefix.lower()
        for entry in reversed(self._entries):
            if entry.lower().startswith(prefix_lower):
                yield entry

    def search_contains(self, substring: str) -> Iterator[str]:
        """Search history for entries containing substring.

        Args:
            substring: Text to search for.

        Yields:
            Matching entries, most recent first.
        """
        substring_lower = substring.lower()
        for entry in reversed(self._entries):
            if substring_lower in entry.lower():
                yield entry

    def clear(self) -> None:
        """Clear all history."""
        self._entries.clear()
        self._position = -1
        self._current_input = ""

        if self._history_file and self._history_file.exists():
            self._history_file.unlink()

    def __len__(self) -> int:
        """Number of entries in history."""
        return len(self._entries)

    def __iter__(self) -> Iterator[str]:
        """Iterate over history, oldest first."""
        return iter(self._entries)

    def _load(self) -> None:
        """Load history from file."""
        if not self._history_file:
            return

        try:
            with self._history_file.open("r", encoding="utf-8") as f:
                for line in f:
                    line = line.strip()
                    if line:
                        self._entries.append(line)
        except Exception:
            pass  # Ignore load errors

    def _save(self) -> None:
        """Save history to file."""
        if not self._history_file:
            return

        try:
            self._history_file.parent.mkdir(parents=True, exist_ok=True)
            with self._history_file.open("w", encoding="utf-8") as f:
                for entry in self._entries:
                    f.write(entry + "\n")
        except Exception:
            pass  # Ignore save errors


# Default history file location
def get_default_history_file() -> Path:
    """Get the default history file path."""
    return Path.home() / ".cleave" / "chat_history"
