using System.IO.Abstractions;
namespace qdr.app.studiou.orders2printpack.EmailStorage
{
///
/// Helper class for working with email items and their file operations.
/// Provides a convenient wrapper around MetadataItem with additional functionality
/// for file system operations, validation, and state management.
///
public class EmailItem
{
#region Private Fields
///
/// The underlying metadata item containing email and processing information
///
private readonly MetadataItem _metadata;
///
/// Base directory path where email item directories are located
///
private readonly string _basePath;
///
/// File system abstraction for testable file operations
///
private readonly IFileSystem _fileSystem;
#endregion
#region Constructor
///
/// Initializes a new instance of the EmailItem class
///
/// The metadata item containing email information
/// Base directory path for file operations
/// File system abstraction for file operations
/// Thrown when metadata, basePath, or fileSystem is null
public EmailItem(MetadataItem metadata, string basePath, IFileSystem fileSystem)
{
_metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
_basePath = basePath ?? throw new ArgumentNullException(nameof(basePath));
_fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
}
#endregion
#region Public Properties
///
/// Gets the underlying metadata item
///
public MetadataItem Metadata => _metadata;
///
/// Gets the full directory path for this email item
/// Combines the base path with the directory name from metadata
///
public string DirectoryPath => _fileSystem.Path.Combine(_basePath, _metadata.DirectoryName);
///
/// Gets a value indicating whether the directory exists on the file system
///
public bool DirectoryExists => _fileSystem.Directory.Exists(DirectoryPath);
///
/// Gets all JPG files in the email item's directory
/// Returns an empty enumerable if the directory doesn't exist
///
public IEnumerable JpgFiles =>
DirectoryExists ? _fileSystem.Directory.GetFiles(DirectoryPath, "*.jpg") : Enumerable.Empty();
///
/// Gets the count of JPG files in the directory
///
public int FileCount => JpgFiles.Count();
///
/// Gets the total size in bytes of all JPG files in the directory
///
public long TotalFileSize => JpgFiles.Sum(f => _fileSystem.FileInfo.New(f).Length);
///
/// Gets a value indicating whether this item is ready for processing
/// Checks that the state is Ready, directory exists, and contains files
///
public bool IsReadyForProcessing =>
_metadata.State == EmailStateEnum.Ready && DirectoryExists && FileCount > 0;
///
/// Gets a value indicating whether this item can be reset
/// Items cannot be reset while they are being processed or uploaded
///
public bool CanBeReset =>
_metadata.State != EmailStateEnum.Processing &&
_metadata.State != EmailStateEnum.Uploading;
///
/// Gets the normalized filename for the recipient (safe for file system)
/// Replaces @ with _at_ and . with _dot_ to create filesystem-safe names
///
public string NormalizedRecipient =>
_metadata.EmailAddress.Replace("@", "_at_").Replace(".", "_dot_");
#endregion
#region Public Methods
///
/// Generates the zip filename for this item based on recipient and timestamp
///
/// Optional timestamp to use, defaults to current time
/// A formatted zip filename in the format: studioufoto_{recipient}_{timestamp}.zip
public string GenerateZipFileName(DateTime? timestamp = null) =>
$"studioufoto_{NormalizedRecipient}_{(timestamp ?? DateTime.Now):yyyyMMdd_HHmmss}.zip";
///
/// Validates that the item is in a consistent state for processing
///
/// A tuple containing validation result and list of issues found
public (bool IsValid, List Issues) Validate()
{
var issues = new List();
// Check required email address
if (string.IsNullOrEmpty(_metadata.EmailAddress))
issues.Add("Email address is required");
// Check directory and files existence
if (!DirectoryExists)
issues.Add($"Directory does not exist: {DirectoryPath}");
else if (FileCount == 0)
issues.Add("No JPG files found in directory");
// Check required email content
if (string.IsNullOrEmpty(_metadata.Subject))
issues.Add("Email subject is required");
if (string.IsNullOrEmpty(_metadata.Body))
issues.Add("Email body is required");
return (issues.Count == 0, issues);
}
///
/// Gets a summary of the item for display purposes
/// Includes recipient, file count, current state, and associated orders
///
/// A formatted summary string
public string GetSummary() =>
$"{_metadata.EmailAddress} - {FileCount} files, {_metadata.State}, Orders: {_metadata.Orders}";
///
/// Gets detailed file information for all JPG files in the directory
///
/// Collection of file information objects
public IEnumerable GetFileDetails() =>
JpgFiles.Select(f => _fileSystem.FileInfo.New(f));
///
/// Checks if a specific file exists in the email item's directory
///
/// Name of the file to check
/// True if the file exists, false otherwise
public bool FileExists(string fileName)
{
if (string.IsNullOrEmpty(fileName))
return false;
var filePath = _fileSystem.Path.Combine(DirectoryPath, fileName);
return _fileSystem.File.Exists(filePath);
}
///
/// Gets the full path for a file within the email item's directory
///
/// Name of the file
/// Full path to the file
public string GetFilePath(string fileName) =>
_fileSystem.Path.Combine(DirectoryPath, fileName);
///
/// Creates the email item's directory if it doesn't exist
///
/// True if directory was created or already exists, false if creation failed
public bool EnsureDirectoryExists()
{
try
{
if (!DirectoryExists)
{
_fileSystem.Directory.CreateDirectory(DirectoryPath);
}
return true;
}
catch
{
return false;
}
}
///
/// Gets file information for a specific file in the directory
///
/// Name of the file
/// File information object, or null if file doesn't exist
public IFileInfo? GetFileInfo(string fileName)
{
if (string.IsNullOrEmpty(fileName))
return null;
var filePath = GetFilePath(fileName);
return _fileSystem.File.Exists(filePath) ? _fileSystem.FileInfo.New(filePath) : null;
}
#endregion
}
}