using BomLocalService.Models; using BomLocalService.Services.Interfaces.Registration; namespace BomLocalService.Services.Interfaces; /// /// Service interface for managing cached radar screenshot files and metadata. /// Handles file system operations for storing and retrieving cached BOM radar screenshots. /// public interface ICacheService : ISingletonService { /// /// Gets the cached screenshot folder path and associated metadata for a location and data type. /// Searches for cache folders matching the location pattern and loads the corresponding metadata JSON file. /// /// The suburb name (e.g., "Pomona", "Brisbane") /// The Australian state abbreviation (e.g., "QLD", "NSW", "VIC") /// The type of cached data to retrieve /// Optional folder path to exclude from search (e.g., folder currently being written to) /// Cancellation token to cancel the operation /// Tuple containing the cache folder path and metadata, or (null, null) if not found Task<(string? cacheFolderPath, LastUpdatedInfo? metadata)> GetCachedScreenshotWithMetadataAsync( string suburb, string state, CachedDataType dataType, string? excludeFolder = null, CancellationToken cancellationToken = default); /// /// Gets all complete cache folders for a location, ordered by timestamp (oldest first). /// Returns basic folder information without loading all frame data. /// /// The suburb name (e.g., "Pomona", "Brisbane") /// The Australian state abbreviation (e.g., "QLD", "NSW", "VIC") /// Cancellation token to cancel the operation /// List of cache folders with available data types Task> GetAllCacheFoldersAsync( string suburb, string state, CancellationToken cancellationToken = default); /// /// Gets frames from a specific cache folder and data type. /// /// The suburb name (e.g., "Pomona", "Brisbane") /// The Australian state abbreviation (e.g., "QLD", "NSW", "VIC") /// The cache folder name /// The type of cached data to retrieve /// Cancellation token to cancel the operation /// List of cached frames, or empty list if not found Task> GetFramesFromCacheFolderAsync( string suburb, string state, string cacheFolderName, CachedDataType dataType, CancellationToken cancellationToken = default); /// /// Gets all cached frames for a location. /// /// The suburb name (e.g., "Pomona", "Brisbane") /// The Australian state abbreviation (e.g., "QLD", "NSW", "VIC") /// Cancellation token to cancel the operation /// List of cached frames, or empty list if not found Task> GetCachedFramesAsync( string suburb, string state, CancellationToken cancellationToken = default); /// /// Gets a specific cached frame for a location. /// /// The suburb name (e.g., "Pomona", "Brisbane") /// The Australian state abbreviation (e.g., "QLD", "NSW", "VIC") /// Frame index (0-6) /// Cancellation token to cancel the operation /// The cached frame, or null if not found Task GetCachedFrameAsync( string suburb, string state, int frameIndex, CancellationToken cancellationToken = default); /// /// Saves metadata JSON file in a cache folder. /// Creates a metadata.json file in the specified cache folder. /// /// Full path to the cache folder /// Metadata to save (observation time, forecast time, weather station, distance) /// Cancellation token to cancel the operation Task SaveMetadataAsync(string cacheFolderPath, LastUpdatedInfo metadata, CancellationToken cancellationToken = default); /// /// Saves frame metadata (frame index and observation time) to a frames.json file in the data type subfolder. /// /// Full path to the cache folder /// The type of cached data /// List of frames with their metadata /// Cancellation token to cancel the operation Task SaveFramesMetadataAsync(string cacheFolderPath, CachedDataType dataType, List frames, CancellationToken cancellationToken = default); /// /// Checks if cached metadata is still valid (not expired). /// Cache is valid if observation time + expiration buffer (typically 15.5 minutes) is still in the future. /// BOM updates observations every 15 minutes, so the buffer accounts for timing variations. /// /// The metadata to validate, or null /// True if metadata exists and cache is still valid, false otherwise bool IsCacheValid(LastUpdatedInfo? metadata); /// /// Gets the file system path to the most recent cached screenshot for a location. /// Returns files ordered by creation time, most recent first. /// /// The suburb name (e.g., "Pomona", "Brisbane") /// The Australian state abbreviation (e.g., "QLD", "NSW", "VIC") /// Cancellation token to cancel the operation /// File system path to the cached screenshot, or empty string if not found Task GetCachedScreenshotPathAsync(string suburb, string state, CancellationToken cancellationToken = default); /// /// Deletes all cached folders (containing frames and metadata) for a location. /// /// The suburb name (e.g., "Pomona", "Brisbane") /// The Australian state abbreviation (e.g., "QLD", "NSW", "VIC") /// Cancellation token to cancel the operation /// True if any folders were deleted, false if no cached folders existed Task DeleteCachedLocationAsync(string suburb, string state, CancellationToken cancellationToken = default); /// /// Gets the cache directory path where screenshots and metadata are stored. /// /// The full path to the cache directory string GetCacheDirectory(); /// /// Cleans up incomplete cache folders (e.g., from a previous crash or restart). /// Scans all cache folders and deletes any that are incomplete (missing frames, metadata, etc.). /// This should be called on application startup to recover from interrupted cache updates. /// /// The number of incomplete folders that were deleted int CleanupIncompleteCacheFolders(); /// /// Checks if a location is currently being updated (has an active cache folder being written to). /// bool IsLocationUpdating(string locationKey); /// /// Gets the active cache folder path for a location (if one is being written to). /// string? GetActiveCacheFolder(string locationKey); /// /// Sets the active cache folder for a location (indicates a cache update is in progress). /// void SetActiveCacheFolder(string locationKey, string cacheFolderPath); /// /// Clears the active cache folder for a location (indicates cache update is complete). /// void ClearActiveCacheFolder(string locationKey); /// /// Creates a new cache folder for a location and timestamp. /// Creates the folder structure and ensures data type subfolders are ready. /// string CreateCacheFolder(string suburb, string state, string timestamp); /// /// Deletes an incomplete cache folder (cleanup on error). /// Only deletes if the folder is incomplete (missing required files). /// bool TryDeleteIncompleteCacheFolder(string cacheFolderPath); /// /// Deletes an empty cache folder. /// bool TryDeleteEmptyCacheFolder(string cacheFolderPath); /// /// Gets cache status information for a location and data type without triggering an update. /// Returns information about whether cache exists, is valid, is updating, etc. /// /// The suburb name (e.g., "Pomona", "Brisbane") /// The Australian state abbreviation (e.g., "QLD", "NSW", "VIC") /// The type of cached data to check /// The number of minutes after observation time that cache expires (will be cast to int) /// The interval in minutes that the background cache management service checks for updates /// Cancellation token to cancel the operation /// Cache status information Task GetCacheStatusAsync( string suburb, string state, CachedDataType dataType, int cacheExpirationMinutes, int cacheManagementCheckIntervalMinutes, CancellationToken cancellationToken = default); /// /// Records progress update for a cache update operation using cacheFolderPath. /// This is useful when locationKey is not directly available (e.g., in ScrapingService). /// /// The cache folder path being updated /// The current phase of the update /// The current frame being captured (if in CapturingFrames phase) /// The total number of frames to capture void RecordUpdateProgressByFolder(string cacheFolderPath, CacheUpdatePhase phase, int? currentFrame = null, int? totalFrames = null); /// /// Gets the estimated remaining seconds for an in-progress cache update. /// Returns 0 if not updating or no metrics available. /// /// The location key (suburb_state) /// Estimated remaining seconds, or 0 if not updating or no metrics int GetEstimatedRemainingSeconds(string locationKey); /// /// Records step completion timing for metrics tracking. /// /// The name of the step /// The duration of the step in seconds void RecordStepCompletion(string stepName, double durationSeconds); /// /// Gets the average duration for a specific step from historical data. /// /// The name of the step /// Average duration in seconds, or 0 if no data available double GetAverageStepDuration(string stepName); /// /// Gets step performance metrics for debugging/logging. /// /// Dictionary mapping step names to their average durations Dictionary GetStepMetrics(); /// /// Gets the average total duration of cache updates from recent metrics. /// Uses median for robustness against outliers. /// /// Average total duration in seconds, or 0 if no data available double GetAverageTotalDuration(); }