"""
Recovery Manager Module
Handles backup and restoration of files with safety mechanisms.
"""

import os
import shutil
import tempfile
from datetime import datetime
from pathlib import Path
from typing import Optional


class RecoveryManager:
    """
    Manages backup and recovery operations for file integrity checks.
    Provides safe restoration with backup and rollback capabilities.
    """
    
    def __init__(self, backup_dir: str = '/var/lib/stellarmate/integrity/backups'):
        """
        Initialize the recovery manager.
        
        Args:
            backup_dir: Directory to store backups
        """
        self.backup_dir = backup_dir
        os.makedirs(backup_dir, exist_ok=True)
    
    def create_backup(self, file_path: str) -> Optional[str]:
        """
        Create a backup of a file before modification.
        
        Args:
            file_path: Path to file to backup
            
        Returns:
            Path to backup file, or None if failed
        """
        if not os.path.exists(file_path):
            return None
        
        try:
            # Generate backup filename with timestamp
            timestamp = datetime.now().strftime('%Y%m%d-%H%M%S')
            filename = os.path.basename(file_path)
            backup_filename = f"{filename}.{timestamp}"
            backup_path = os.path.join(self.backup_dir, backup_filename)
            
            # Ensure backup directory structure
            os.makedirs(os.path.dirname(backup_path), exist_ok=True)
            
            # Copy file with metadata
            shutil.copy2(file_path, backup_path)
            
            return backup_path
            
        except Exception as e:
            return None
    
    def restore_from_reference(self, file_path: str, reference_path: str,
                              create_backup: bool = True) -> bool:
        """
        Restore a file from its reference copy.
        
        Args:
            file_path: Path to file to restore
            reference_path: Path to reference file
            create_backup: Whether to backup current file first
            
        Returns:
            True if successful, False otherwise
        """
        if not os.path.exists(reference_path):
            return False
        
        try:
            # Create backup of current file if it exists
            if create_backup and os.path.exists(file_path):
                self.create_backup(file_path)
            
            # Ensure target directory exists
            os.makedirs(os.path.dirname(file_path), exist_ok=True)
            
            # Copy reference to target with atomic operation
            # First copy to temp file, then rename
            temp_fd, temp_path = tempfile.mkstemp(
                dir=os.path.dirname(file_path),
                prefix='.integrity_tmp_'
            )
            
            try:
                os.close(temp_fd)
                shutil.copy2(reference_path, temp_path)
                
                # Atomic rename
                os.replace(temp_path, file_path)
                
                return True
                
            finally:
                # Clean up temp file if it still exists
                if os.path.exists(temp_path):
                    try:
                        os.remove(temp_path)
                    except Exception:
                        pass
            
        except Exception as e:
            return False
    
    def fix_permissions(self, file_path: str, mode: int, uid: int, gid: int) -> bool:
        """
        Fix file permissions and ownership.
        
        Args:
            file_path: Path to file
            mode: Permission mode (e.g., 0o644)
            uid: User ID
            gid: Group ID
            
        Returns:
            True if successful, False otherwise
        """
        if not os.path.exists(file_path):
            return False
        
        try:
            # Set permissions
            os.chmod(file_path, mode)
            
            # Set ownership
            os.chown(file_path, uid, gid)
            
            return True
            
        except PermissionError:
            # Need root permissions
            return False
        except Exception:
            return False
    
    def rollback_from_backup(self, file_path: str, backup_path: str) -> bool:
        """
        Rollback a file from its backup.
        
        Args:
            file_path: Path to file to rollback
            backup_path: Path to backup file
            
        Returns:
            True if successful, False otherwise
        """
        if not os.path.exists(backup_path):
            return False
        
        try:
            shutil.copy2(backup_path, file_path)
            return True
        except Exception:
            return False
    
    def cleanup_old_backups(self, days: int = 30) -> int:
        """
        Remove backup files older than specified days.
        
        Args:
            days: Number of days to keep backups
            
        Returns:
            Number of files deleted
        """
        if not os.path.exists(self.backup_dir):
            return 0
        
        deleted_count = 0
        current_time = datetime.now().timestamp()
        max_age = days * 86400  # Convert days to seconds
        
        try:
            for root, dirs, files in os.walk(self.backup_dir):
                for filename in files:
                    file_path = os.path.join(root, filename)
                    file_age = current_time - os.path.getmtime(file_path)
                    
                    if file_age > max_age:
                        try:
                            os.remove(file_path)
                            deleted_count += 1
                        except Exception:
                            pass
            
            return deleted_count
            
        except Exception:
            return deleted_count
    
    def get_backup_list(self, file_path: str) -> list:
        """
        Get list of all backups for a specific file.
        
        Args:
            file_path: Path to file
            
        Returns:
            List of backup paths sorted by timestamp (newest first)
        """
        if not os.path.exists(self.backup_dir):
            return []
        
        filename = os.path.basename(file_path)
        backups = []
        
        try:
            for item in os.listdir(self.backup_dir):
                if item.startswith(filename + '.'):
                    backup_path = os.path.join(self.backup_dir, item)
                    if os.path.isfile(backup_path):
                        backups.append(backup_path)
            
            # Sort by modification time (newest first)
            backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
            
            return backups
            
        except Exception:
            return []
    
    def verify_restoration(self, file_path: str, reference_path: str) -> bool:
        """
        Verify that a file matches its reference after restoration.
        
        Args:
            file_path: Path to restored file
            reference_path: Path to reference file
            
        Returns:
            True if files match, False otherwise
        """
        if not os.path.exists(file_path) or not os.path.exists(reference_path):
            return False
        
        try:
            # Compare file contents
            with open(file_path, 'rb') as f1, open(reference_path, 'rb') as f2:
                return f1.read() == f2.read()
        except Exception:
            return False
