"""Update Service Layer. This service provides software update operations that can be consumed by multiple interfaces (REST API, BLE GATT, etc.). """ from typing import Optional, Dict, Any from ..managers.update_manager import UpdateManager, UpdateProgress, UpdateStatus from .pm3_service import PM3ServiceError, PM3ServiceResult class UpdateService: """Update service layer for software update management. This service can be used by multiple interfaces: - REST API (FastAPI endpoints) - BLE GATT (Bluetooth handlers) - Plugin system (future) It encapsulates: - Update checking - Update downloading - Update installation - Progress monitoring """ def __init__(self, update_manager: Optional[UpdateManager] = None): """Initialize update service. Args: update_manager: Update manager instance (creates new if not provided) """ from ..managers.update_manager import get_update_manager self.update_manager = update_manager or get_update_manager() async def check_for_updates(self) -> PM3ServiceResult: """Check for available updates. Returns: PM3ServiceResult with update availability and information """ try: result = await self.update_manager.check_for_updates() return PM3ServiceResult( success=True, data=result ) except Exception as e: return PM3ServiceResult( success=False, error=PM3ServiceError( code="update_check_error", message="Failed to check for updates", details=str(e) ) ) async def download_update(self) -> PM3ServiceResult: """Download the latest available update. Returns: PM3ServiceResult indicating download success/failure """ try: success = await self.update_manager.download_update() if success: return PM3ServiceResult( success=True, data={ "message": "Update downloaded successfully", "ready_to_install": True } ) else: return PM3ServiceResult( success=False, error=PM3ServiceError( code="download_failed", message="Update download failed" ) ) except ValueError as e: # No update available return PM3ServiceResult( success=False, error=PM3ServiceError( code="no_update_available", message=str(e) ) ) except Exception as e: return PM3ServiceResult( success=False, error=PM3ServiceError( code="update_download_error", message="Error downloading update", details=str(e) ) ) async def install_update(self) -> PM3ServiceResult: """Install the downloaded update. Returns: PM3ServiceResult indicating installation success/failure """ try: success = await self.update_manager.install_update() if success: return PM3ServiceResult( success=True, data={ "message": "Update installed successfully", "requires_restart": True } ) else: return PM3ServiceResult( success=False, error=PM3ServiceError( code="installation_failed", message="Update installation failed" ) ) except ValueError as e: # No update downloaded return PM3ServiceResult( success=False, error=PM3ServiceError( code="no_update_downloaded", message=str(e) ) ) except Exception as e: return PM3ServiceResult( success=False, error=PM3ServiceError( code="update_install_error", message="Error installing update", details=str(e) ) ) async def get_progress(self) -> PM3ServiceResult: """Get current update progress. Returns: PM3ServiceResult with progress information """ try: progress = await self.update_manager.get_progress() return PM3ServiceResult( success=True, data={ "status": progress.status.value, "current_version": progress.current_version, "available_version": progress.available_version, "download_progress": progress.download_progress, "error_message": progress.error_message, "last_check": progress.last_check } ) except Exception as e: return PM3ServiceResult( success=False, error=PM3ServiceError( code="progress_error", message="Failed to get update progress", details=str(e) ) ) async def get_release_notes( self, version: Optional[str] = None ) -> PM3ServiceResult: """Get release notes for a specific version or latest. Args: version: Version to get notes for (latest if None) Returns: PM3ServiceResult with release notes """ try: notes = await self.update_manager.get_release_notes(version) return PM3ServiceResult( success=True, data={ "version": version or "latest", "release_notes": notes } ) except Exception as e: return PM3ServiceResult( success=False, error=PM3ServiceError( code="release_notes_error", message="Failed to get release notes", details=str(e) ) ) async def check_and_download_update(self) -> PM3ServiceResult: """Combined operation: check for updates and download if available. Returns: PM3ServiceResult with check and download status """ try: # First check for updates check_result = await self.check_for_updates() if not check_result.success: return check_result # If update available, download it if check_result.data.get("update_available"): download_result = await self.download_update() if download_result.success: return PM3ServiceResult( success=True, data={ "message": "Update checked and downloaded", "update_info": check_result.data, "ready_to_install": True } ) else: return download_result else: return PM3ServiceResult( success=True, data={ "message": "System is up to date", "update_available": False, "current_version": check_result.data.get("current_version") } ) except Exception as e: return PM3ServiceResult( success=False, error=PM3ServiceError( code="check_download_error", message="Error checking and downloading update", details=str(e) ) ) async def full_update(self) -> PM3ServiceResult: """Full update workflow: check, download, and install. Returns: PM3ServiceResult with complete update status """ try: # Check for updates check_result = await self.check_for_updates() if not check_result.success: return check_result if not check_result.data.get("update_available"): return PM3ServiceResult( success=True, data={ "message": "System is already up to date", "update_performed": False } ) # Download update download_result = await self.download_update() if not download_result.success: return download_result # Install update install_result = await self.install_update() if not install_result.success: return install_result return PM3ServiceResult( success=True, data={ "message": "Update completed successfully", "update_performed": True, "previous_version": check_result.data.get("current_version"), "new_version": check_result.data.get("latest_version"), "requires_restart": True } ) except Exception as e: return PM3ServiceResult( success=False, error=PM3ServiceError( code="full_update_error", message="Error performing full update", details=str(e) ) )