"""GitService - Git repository status service.

Contract: CNT-TUI-SVC-002
Traceability: UX-001
"""

import subprocess
from dataclasses import dataclass
from pathlib import Path


@dataclass(frozen=True)
class GitStatus:
    """Represents the current Git repository status."""

    branch: str
    is_clean: bool
    changed_files: int
    ahead: int
    behind: int

    @property
    def has_changes(self) -> bool:
        """Check if there are uncommitted changes."""
        return not self.is_clean

    @property
    def sync_status(self) -> str:
        """Get human-readable sync status."""
        if self.ahead > 0 and self.behind > 0:
            return f"↑{self.ahead} ↓{self.behind}"
        elif self.ahead > 0:
            return f"↑{self.ahead}"
        elif self.behind > 0:
            return f"↓{self.behind}"
        return "synced"


class GitService:
    """Service for querying Git repository status.

    Uses subprocess to run Git commands. Designed for TUI display,
    not for modifying the repository.
    """

    def __init__(self, timeout: float = 5.0) -> None:
        """Initialize with optional timeout.

        Args:
            timeout: Command timeout in seconds
        """
        self._timeout = timeout

    def get_status(self, path: Path) -> GitStatus | None:
        """Get the current Git repository status.

        Args:
            path: Path within the Git repository

        Returns:
            GitStatus or None if not a Git repository or Git unavailable
        """
        try:
            # Check if in a Git repository
            if not self._is_git_repo(path):
                return None

            # Get branch name
            branch = self._get_branch(path)

            # Get status
            changed_files = self._get_changed_count(path)

            # Get ahead/behind counts
            ahead, behind = self._get_ahead_behind(path)

            return GitStatus(
                branch=branch,
                is_clean=changed_files == 0,
                changed_files=changed_files,
                ahead=ahead,
                behind=behind,
            )
        except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
            return None

    def _is_git_repo(self, path: Path) -> bool:
        """Check if path is inside a Git repository."""
        result = subprocess.run(
            ["git", "rev-parse", "--is-inside-work-tree"],
            cwd=path,
            capture_output=True,
            text=True,
            timeout=self._timeout,
        )
        return result.returncode == 0

    def _get_branch(self, path: Path) -> str:
        """Get current branch name."""
        result = subprocess.run(
            ["git", "rev-parse", "--abbrev-ref", "HEAD"],
            cwd=path,
            capture_output=True,
            text=True,
            timeout=self._timeout,
        )
        if result.returncode == 0:
            return result.stdout.strip()
        return "unknown"

    def _get_changed_count(self, path: Path) -> int:
        """Get count of changed files."""
        result = subprocess.run(
            ["git", "status", "--porcelain"],
            cwd=path,
            capture_output=True,
            text=True,
            timeout=self._timeout,
        )
        if result.returncode == 0:
            lines = [line for line in result.stdout.splitlines() if line.strip()]
            return len(lines)
        return 0

    def _get_ahead_behind(self, path: Path) -> tuple[int, int]:
        """Get ahead/behind counts relative to upstream."""
        result = subprocess.run(
            ["git", "rev-list", "--left-right", "--count", "HEAD...@{upstream}"],
            cwd=path,
            capture_output=True,
            text=True,
            timeout=self._timeout,
        )
        if result.returncode == 0:
            parts = result.stdout.strip().split()
            if len(parts) == 2:
                return int(parts[0]), int(parts[1])
        return 0, 0

    def is_available(self) -> bool:
        """Check if Git is available on the system."""
        try:
            result = subprocess.run(
                ["git", "--version"],
                capture_output=True,
                timeout=self._timeout,
            )
            return result.returncode == 0
        except (FileNotFoundError, OSError):
            return False
