""" Abstract interfaces for history tracking. Defines the contract for history backends and query services. """ from abc import ABC, abstractmethod from pathlib import Path from typing import List, Optional, Dict, Any from .models import Commit, Branch, DiffResult, HistoryEntry, HistoryConfig class IHistoryBackend(ABC): """ Abstract interface for history storage backends. Implementations can use git, SQLite, or other storage mechanisms. """ @abstractmethod def initialize(self, directory: Path, config: HistoryConfig) -> None: """ Initialize the history backend. Args: directory: Root directory for the space config: History configuration """ pass @abstractmethod def is_initialized(self, directory: Path) -> bool: """ Check if history is initialized for a directory. Args: directory: Directory to check Returns: True if history tracking is initialized """ pass @abstractmethod def commit( self, directory: Path, message: str, files: Optional[List[str]] = None, author: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None, ) -> Commit: """ Create a new commit. Args: directory: Root directory message: Commit message files: Specific files to commit (None for all changes) author: Author string (name ) metadata: Additional metadata to store Returns: The created commit """ pass @abstractmethod def get_commit(self, directory: Path, commit_id: str) -> Optional[Commit]: """ Get a commit by ID. Args: directory: Root directory commit_id: Commit identifier Returns: The commit if found, None otherwise """ pass @abstractmethod def get_log( self, directory: Path, limit: int = 50, offset: int = 0, path: Optional[str] = None, ) -> List[Commit]: """ Get commit history. Args: directory: Root directory limit: Maximum number of commits offset: Number of commits to skip path: Filter by file path Returns: List of commits, newest first """ pass @abstractmethod def get_diff( self, directory: Path, old_version: Optional[str] = None, new_version: Optional[str] = None, path: Optional[str] = None, ) -> List[DiffResult]: """ Get diff between versions. Args: directory: Root directory old_version: Old commit ID (None for working directory) new_version: New commit ID (None for working directory) path: Filter by file path Returns: List of diff results """ pass @abstractmethod def checkout( self, directory: Path, version: str, path: Optional[str] = None, ) -> bool: """ Checkout a specific version. Args: directory: Root directory version: Commit ID or ref to checkout path: Specific file to checkout (None for all) Returns: True if successful """ pass @abstractmethod def get_file_at_version( self, directory: Path, path: str, version: str, ) -> Optional[str]: """ Get file content at a specific version. Args: directory: Root directory path: File path relative to directory version: Commit ID or ref Returns: File content as string, or None if not found """ pass @abstractmethod def list_branches(self, directory: Path) -> List[Branch]: """ List all branches. Args: directory: Root directory Returns: List of branches """ pass @abstractmethod def create_branch( self, directory: Path, name: str, start_point: Optional[str] = None, ) -> Branch: """ Create a new branch. Args: directory: Root directory name: Branch name start_point: Starting commit/ref (None for HEAD) Returns: The created branch """ pass @abstractmethod def switch_branch(self, directory: Path, name: str) -> bool: """ Switch to a branch. Args: directory: Root directory name: Branch name Returns: True if successful """ pass @abstractmethod def get_current_branch(self, directory: Path) -> Optional[str]: """ Get the current branch name. Args: directory: Root directory Returns: Branch name or None if detached """ pass @abstractmethod def has_changes(self, directory: Path) -> bool: """ Check if there are uncommitted changes. Args: directory: Root directory Returns: True if there are uncommitted changes """ pass class IHistoryQuery(ABC): """ Abstract interface for history queries. Provides higher-level query operations on top of the backend. """ @abstractmethod def get_history( self, space_id: str, limit: int = 50, offset: int = 0, path: Optional[str] = None, ) -> List[HistoryEntry]: """ Get history entries for a space. Args: space_id: Space identifier limit: Maximum entries offset: Skip count path: Filter by document path Returns: List of history entries """ pass @abstractmethod def get_version_content( self, space_id: str, document_path: str, version: str, ) -> Optional[str]: """ Get document content at a specific version. Args: space_id: Space identifier document_path: Path to document version: Version identifier Returns: Document content or None """ pass @abstractmethod def compare_versions( self, space_id: str, document_path: str, old_version: str, new_version: Optional[str] = None, ) -> Optional[DiffResult]: """ Compare two versions of a document. Args: space_id: Space identifier document_path: Path to document old_version: Old version ID new_version: New version ID (None for current) Returns: Diff result or None """ pass @abstractmethod def search_history( self, space_id: str, query: str, limit: int = 20, ) -> List[HistoryEntry]: """ Search commit messages. Args: space_id: Space identifier query: Search query limit: Maximum results Returns: Matching history entries """ pass @abstractmethod def restore_version( self, space_id: str, document_path: str, version: str, ) -> bool: """ Restore a document to a specific version. Args: space_id: Space identifier document_path: Path to document version: Version to restore Returns: True if successful """ pass