using File = TagLib.File;

namespace adas_core.Domain.Utils;

/// <summary>
/// Provides static utility methods for handling media-related operations.
/// </summary>
public static class MediaUtils
{
    public static readonly Dictionary<string, string> Mapping = new(StringComparer.InvariantCultureIgnoreCase)
    {
        { ".aac", "audio/aac" },
        { ".abw", "application/x-abiword" },
        { ".apng", "image/apng" },
        { ".arc", "application/x-freearc" },
        { ".avif", "image/avif" },
        { ".avi", "video/x-msvideo" },
        { ".azw", "application/vnd.amazon.ebook" },
        { ".bin", "application/octet-stream" },
        { ".bmp", "image/bmp" },
        { ".bz", "application/x-bzip" },
        { ".bz2", "application/x-bzip2" },
        { ".cda", "application/x-cdf" },
        { ".csh", "application/x-csh" },
        { ".css", "text/css" },
        { ".csv", "text/csv" },
        { ".doc", "application/msword" },
        { ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
        { ".eot", "application/vnd.ms-fontobject" },
        { ".epub", "application/epub+zip" },
        { ".gz", "application/gzip" },
        { ".gif", "image/gif" },
        { ".htm", "text/html" },
        { ".html", "text/html" },
        { ".ico", "image/vnd.microsoft.icon" },
        { ".ics", "text/calendar" },
        { ".jar", "application/java-archive" },
        { ".jpeg", "image/jpeg" },
        { ".jpg", "image/jpeg" },
        { ".js", "text/javascript" },
        { ".json", "application/json" },
        { ".jsonld", "application/ld+json" },
        { ".mid", "audio/midi" },
        { ".midi", "audio/midi" },
        { ".mjs", "text/javascript" },
        { ".mp3", "audio/mpeg" },
        { ".mp4", "video/mp4" },
        { ".mpeg", "video/mpeg" },
        { ".mpkg", "application/vnd.apple.installer+xml" },
        { ".odp", "application/vnd.oasis.opendocument.presentation" },
        { ".ods", "application/vnd.oasis.opendocument.spreadsheet" },
        { ".odt", "application/vnd.oasis.opendocument.text" },
        { ".oga", "audio/ogg" },
        { ".ogv", "video/ogg" },
        { ".ogx", "application/ogg" },
        { ".opus", "audio/ogg" },
        { ".otf", "font/otf" },
        { ".png", "image/png" },
        { ".pdf", "application/pdf" },
        { ".php", "application/x-httpd-php" },
        { ".ppt", "application/vnd.ms-powerpoint" },
        { ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" },
        { ".rar", "application/vnd.rar" },
        { ".rtf", "application/rtf" },
        { ".sh", "application/x-sh" },
        { ".svg", "image/svg+xml" },
        { ".tar", "application/x-tar" },
        { ".tif", "image/tiff" },
        { ".tiff", "image/tiff" },
        { ".ts", "video/mp2t" },
        { ".ttf", "font/ttf" },
        { ".txt", "text/plain" },
        { ".vsd", "application/vnd.visio" },
        { ".wav", "audio/wav" },
        { ".weba", "audio/webm" },
        { ".webm", "video/webm" },
        { ".webp", "image/webp" },
        { ".woff", "font/woff" },
        { ".woff2", "font/woff2" },
        { ".xhtml", "application/xhtml+xml" },
        { ".xls", "application/vnd.ms-excel" },
        { ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
        { ".xml", "application/xml" },
        { ".xul", "application/vnd.mozilla.xul+xml" },
        { ".zip", "application/zip" },
        { ".3gp", "video/3gpp" },
        { ".3g2", "video/3gpp2" },
        { ".7z", "application/x-7z-compressed" },
        { ".flv", "video/x-flv" },
        { ".m3u8", "application/x-mpegURL" },
        { ".mov", "video/quicktime" },
        { ".wmv", "video/x-ms-wmv" }
    };

    /// <summary>
    /// Determines the MIME type associated with the file extension of the specified path.
    /// Performs a case-insensitive lookup against a known extension mapping and falls back to <c>application/octet-stream</c> when the extension is not recognized.
    /// </summary>
    /// <param name="filePath">The file path whose extension is used to resolve the MIME type.</param>
    /// <returns>The corresponding MIME type string if the extension is found in the mapping; otherwise, the default <c>application/octet-stream</c> value.</returns>
    public static string GetMimeType(string filePath)
        {
            var extension = Path.GetExtension(filePath).ToLowerInvariant();
            return Mapping.TryGetValue(extension, out var mimeType) ? mimeType : "application/octet-stream";
        }

    /// <summary>
    /// Determines whether the specified file path corresponds to a supported video file by comparing its extension against a predefined list of video formats (e.g., .mp4, .avi, .mkv, .mov).
    /// The comparison is case-insensitive.
    /// </summary>
    /// <param name="filePath">The path of the file to evaluate.</param>
    /// <returns><c>true</c> if the file extension matches one of the supported video extensions; otherwise, <c>false</c>.</returns>
    public static bool IsVideoFile(string filePath)
        {
            // Extensiones de video soportadas
            var videoExtensions = new[]
                { ".mp4", ".avi", ".mkv", ".mpeg", ".ogv", ".webm", ".3gp", ".3g2", ".mov", ".wmv", ".m3u8" };
            return videoExtensions.Contains(Path.GetExtension(filePath), StringComparer.InvariantCultureIgnoreCase);
        }

    /// <summary>
    /// Retrieves the duration of the video at the specified path, expressed in milliseconds.
    /// Returns null if the duration cannot be read, with the underlying error logged to the console.
    /// </summary>
    /// <param name="videoPath">The file path of the video whose duration should be retrieved.</param>
    /// <returns>The video duration in milliseconds, or null if an error occurs while reading the file.</returns>
    public static long? GetVideoDuration(string videoPath)
        {
            try
            {
                var file = File.Create(videoPath);
                var duration = file.Properties.Duration;
                return (long)duration.TotalMilliseconds;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
                return null;
            }
        }
}