using Microsoft.AspNetCore.Http;
namespace PowderCoating.Application.Services;
///
/// Shared file validation and content-type resolution used across all blob storage services.
///
public static class BlobFileHelper
{
///
/// Validates an uploaded file against an extension allowlist and a maximum size.
/// Returns the normalized (lowercase) extension on success so callers do not re-derive it.
///
public static (bool IsValid, string Extension, string Error) ValidateUpload(
IFormFile? file,
string[] allowedExtensions,
long maxBytes)
{
if (file == null || file.Length == 0)
return (false, string.Empty, "No file provided.");
if (file.Length > maxBytes)
return (false, string.Empty, $"File exceeds the {maxBytes / 1024 / 1024} MB limit.");
var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
if (string.IsNullOrEmpty(extension) || !allowedExtensions.Contains(extension))
return (false, string.Empty, $"File type not allowed. Allowed: {string.Join(", ", allowedExtensions)}.");
return (true, extension, string.Empty);
}
///
/// Maps a file extension to its MIME content type, covering common image formats and
/// document types. Falls back to application/octet-stream.
///
public static string GetContentType(string extension) => extension switch
{
".jpg" or ".jpeg" => "image/jpeg",
".png" => "image/png",
".gif" => "image/gif",
".webp" => "image/webp",
".svg" => "image/svg+xml",
".pdf" => "application/pdf",
".doc" => "application/msword",
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".txt" => "text/plain",
_ => "application/octet-stream"
};
///
/// Strips OS-invalid filename characters from a base filename (no extension), replacing
/// them with underscores to produce a safe blob path segment.
///
public static string SanitizeFileName(string fileName)
{
var sanitized = string.Join("_", fileName.Split(Path.GetInvalidFileNameChars()));
return string.IsNullOrWhiteSpace(sanitized) ? "file" : sanitized;
}
}