"""
Backup and restore functionality for git attribution stripping.

This module provides functions to create backup refs before history rewriting
and restore from those backups if needed.

Key Functions:
    - create_backup_ref: Create backup ref before history rewrite
    - list_backup_refs: List available backup refs
    - restore_from_backup: Restore branch from backup ref
"""

import subprocess
from datetime import datetime
from pathlib import Path

from persuade.constants import GIT_CHECK_IGNORE_TIMEOUT
from persuade.logging import get_logger

from .types import (
    BACKUP_REF_PREFIX,
    GIT_REF_OPERATION_TIMEOUT,
    StripResult,
)

logger = get_logger()


def _get_current_branch(repo_path: Path) -> str | None:
    """Get the current branch name."""
    try:
        result = subprocess.run(
            ["git", "branch", "--show-current"],
            cwd=repo_path,
            capture_output=True,
            text=True,
            check=True,
            timeout=GIT_CHECK_IGNORE_TIMEOUT,
        )
        return result.stdout.strip() or None
    except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
        return None


def create_backup_ref(repo_path: Path, branch_name: str | None = None) -> str | None:
    """
    Create a backup ref before rewriting history.

    Args:
        repo_path: Path to the git repository
        branch_name: Branch name to include in ref (defaults to current branch)

    Returns:
        The backup ref name if created, None on failure
    """
    if branch_name is None:
        branch_name = _get_current_branch(repo_path) or "HEAD"

    # Sanitize branch name for ref
    safe_branch = branch_name.replace("/", "-")
    timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
    backup_ref = f"{BACKUP_REF_PREFIX}/{safe_branch}/{timestamp}"

    try:
        subprocess.run(
            ["git", "update-ref", backup_ref, "HEAD"],
            cwd=repo_path,
            capture_output=True,
            check=True,
            timeout=GIT_CHECK_IGNORE_TIMEOUT,
        )
        logger.info("backup_ref_created", ref=backup_ref)
        return backup_ref
    except subprocess.CalledProcessError as e:
        logger.error(
            "backup_ref_failed",
            error=str(e),
            stderr=e.stderr.decode() if e.stderr else "",
        )
        return None
    except subprocess.TimeoutExpired:
        logger.error("backup_ref_timeout")
        return None


def list_backup_refs(repo_path: Path) -> list[tuple[str, str]]:
    """
    List available backup refs.

    Args:
        repo_path: Path to the git repository

    Returns:
        List of (ref_name, commit_sha) tuples
    """
    try:
        result = subprocess.run(
            ["git", "for-each-ref", "--format=%(refname) %(objectname)", BACKUP_REF_PREFIX],
            cwd=repo_path,
            capture_output=True,
            text=True,
            check=True,
            timeout=GIT_CHECK_IGNORE_TIMEOUT,
        )
        refs = []
        for line in result.stdout.strip().splitlines():
            if line.strip():
                parts = line.strip().split(" ", 1)
                if len(parts) == 2:
                    refs.append((parts[0], parts[1]))
        return refs
    except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
        return []


def restore_from_backup(repo_path: Path, backup_ref: str) -> StripResult:
    """
    Restore a branch from a backup ref.

    Args:
        repo_path: Path to the git repository
        backup_ref: The backup ref to restore from

    Returns:
        StripResult indicating success or failure
    """
    try:
        # Verify the backup ref exists
        result = subprocess.run(
            ["git", "rev-parse", "--verify", backup_ref],
            cwd=repo_path,
            capture_output=True,
            check=False,
            timeout=GIT_CHECK_IGNORE_TIMEOUT,
        )
        if result.returncode != 0:
            return StripResult(
                success=False,
                message=f"Backup ref not found: {backup_ref}",
                error="Backup ref does not exist",
            )

        # Reset current branch to backup
        result = subprocess.run(
            ["git", "reset", "--hard", backup_ref],
            cwd=repo_path,
            capture_output=True,
            check=True,
            timeout=GIT_REF_OPERATION_TIMEOUT,
        )

        logger.info("restore_from_backup_success", ref=backup_ref)
        return StripResult(
            success=True,
            message=f"Successfully restored from backup: {backup_ref}",
            backup_ref=backup_ref,
        )
    except subprocess.CalledProcessError as e:
        logger.error(
            "restore_failed",
            error=str(e),
            stderr=e.stderr.decode() if e.stderr else "",
        )
        return StripResult(
            success=False,
            message="Failed to restore from backup",
            error=e.stderr.decode() if e.stderr else str(e),
        )
    except subprocess.TimeoutExpired:
        return StripResult(
            success=False,
            message="Restore operation timed out",
            error="Timeout",
        )
