using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using MetadataExtractor.Formats.Exif.Makernotes;
using System.Globalization;
using View_by_Distance.Metadata.Models.Stateless.Methods;

namespace View_by_Distance.Metadata.Models.Stateless;

internal abstract class Exif
{

    private static DateTime? GetDateTime(string? value)
    {
        DateTime? result;
        string dateTimeFormat = "yyyy:MM:dd HH:mm:ss";
        string alternateFormat = "ddd MMM dd HH:mm:ss yyyy";
        if (value is not null && DateTime.TryParse(value, out DateTime dateTime))
            result = dateTime;
        else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
            result = dateTime;
        else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
            result = dateTime;
        else
            result = null;
        return result;
    }

    private static Shared.Models.AviDirectory[] GetAviDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.AviDirectory> results = [];
        IEnumerable<MetadataExtractor.Formats.Avi.AviDirectory> aviDirectories = directories.OfType<MetadataExtractor.Formats.Avi.AviDirectory>();
        foreach (MetadataExtractor.Formats.Avi.AviDirectory aviDirectory in aviDirectories)
        {
            if (aviDirectory.Tags.Count == 0)
                continue;
            DateTime? dateTimeOriginal;
            string? duration = aviDirectory.GetDescription(MetadataExtractor.Formats.Avi.AviDirectory.TagDuration);
            string? height = aviDirectory.GetDescription(MetadataExtractor.Formats.Avi.AviDirectory.TagHeight);
            string? width = aviDirectory.GetDescription(MetadataExtractor.Formats.Avi.AviDirectory.TagWidth);
            if (aviDirectory.TryGetDateTime(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal, out DateTime checkDateTime))
                dateTimeOriginal = checkDateTime;
            else
                dateTimeOriginal = GetDateTime(aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal));
            if (dateTimeOriginal is null && duration is null && height is null && width is null)
                continue;
            results.Add(new(dateTimeOriginal, duration, height, width));
        }
        return results.ToArray();
    }

    private static Shared.Models.ExifDirectoryBase[] GetExifBaseDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.ExifDirectoryBase> results = [];
        IEnumerable<ExifDirectoryBase> exifBaseDirectories = directories.OfType<ExifDirectoryBase>();
        foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
        {
            if (exifDirectoryBase.Tags.Count == 0)
                continue;
            DateTime? dateTime;
            DateTime checkDateTime;
            DateTime? dateTimeOriginal;
            DateTime? dateTimeDigitized;
            string? aperture = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagAperture);
            string? applicationNotes = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagApplicationNotes);
            string? artist = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagArtist);
            string? bitsPerSample = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagBitsPerSample);
            string? bodySerialNumber = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagBodySerialNumber);
            string? cameraOwnerName = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagCameraOwnerName);
            string? compressedAverageBitsPerPixel = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagCompressedAverageBitsPerPixel);
            string? compression = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagCompression);
            string? copyright = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagCopyright);
            string? documentName = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagDocumentName);
            string? exifVersion = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagExifVersion);
            string? exposureTime = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagExposureTime);
            string? fileSource = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagFileSource);
            string? imageDescription = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageDescription);
            string? imageHeight = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageHeight);
            string? imageNumber = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageNumber);
            string? imageUniqueId = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageUniqueId);
            string? imageWidth = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageWidth);
            string? isoSpeed = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagIsoSpeed);
            string? lensMake = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensMake);
            string? lensModel = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensModel);
            string? lensSerialNumber = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensSerialNumber);
            string? make = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagMake);
            string? makerNote = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagMakernote);
            string? model = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagModel);
            string? orientation = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagOrientation);
            int? orientationValue = orientation is null ? null : exifDirectoryBase.GetInt32(ExifDirectoryBase.TagOrientation);
            string? rating = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagRating);
            string? ratingPercent = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagRatingPercent);
            string? securityClassification = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagSecurityClassification);
            string? shutterSpeed = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagShutterSpeed);
            string? software = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagSoftware);
            string? timeZone = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagTimeZone);
            string? timeZoneDigitized = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagTimeZoneDigitized);
            string? timeZoneOriginal = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagTimeZoneOriginal);
            string? userComment = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagUserComment);
            string? winAuthor = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinAuthor);
            string? winComment = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinComment);
            string? winKeywords = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinKeywords);
            string? winSubject = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinSubject);
            string? winTitle = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinTitle);
            string? xResolution = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagXResolution);
            string? yResolution = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagYResolution);
            if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTime, out checkDateTime))
                dateTime = checkDateTime;
            else
                dateTime = GetDateTime(exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTime));
            if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTimeOriginal, out checkDateTime))
                dateTimeOriginal = checkDateTime;
            else
                dateTimeOriginal = GetDateTime(exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTimeOriginal));
            if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTimeDigitized, out checkDateTime))
                dateTimeDigitized = checkDateTime;
            else
                dateTimeDigitized = GetDateTime(exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTimeDigitized));
            if (userComment is not null && userComment.Length > 255)
                userComment = "...";
            if (aperture is null
                && applicationNotes is null
                && artist is null
                && bitsPerSample is null
                && bodySerialNumber is null
                && cameraOwnerName is null
                && compressedAverageBitsPerPixel is null
                && compression is null
                && copyright is null
                && dateTime is null
                && dateTimeDigitized is null
                && dateTimeOriginal is null
                && documentName is null
                && exifVersion is null
                && exposureTime is null
                && fileSource is null
                && imageDescription is null
                && imageHeight is null
                && imageNumber is null
                && imageUniqueId is null
                && imageWidth is null
                && isoSpeed is null
                && lensMake is null
                && lensModel is null
                && lensSerialNumber is null
                && make is null
                && makerNote is null
                && model is null
                && orientation is null
                && orientationValue is null
                && rating is null
                && ratingPercent is null
                && securityClassification is null
                && shutterSpeed is null
                && software is null
                && timeZone is null
                && timeZoneDigitized is null
                && timeZoneOriginal is null
                && userComment is null
                && winAuthor is null
                && winComment is null
                && winKeywords is null
                && winSubject is null
                && winTitle is null
                && xResolution is not null
                && yResolution is null)
                continue;
            results.Add(new(aperture,
                            applicationNotes,
                            artist,
                            bitsPerSample,
                            bodySerialNumber,
                            cameraOwnerName,
                            compressedAverageBitsPerPixel,
                            compression,
                            copyright,
                            dateTime,
                            dateTimeDigitized,
                            dateTimeOriginal,
                            documentName,
                            exifVersion,
                            exposureTime,
                            fileSource,
                            imageDescription,
                            imageHeight,
                            imageNumber,
                            imageUniqueId,
                            imageWidth,
                            isoSpeed,
                            lensMake,
                            lensModel,
                            lensSerialNumber,
                            make,
                            makerNote,
                            model,
                            orientation,
                            orientationValue,
                            rating,
                            ratingPercent,
                            securityClassification,
                            shutterSpeed,
                            software,
                            timeZone,
                            timeZoneDigitized,
                            timeZoneOriginal,
                            userComment,
                            winAuthor,
                            winComment,
                            winKeywords,
                            winSubject,
                            winTitle,
                            xResolution,
                            yResolution));
        }
        return results.ToArray();
    }

    private static Shared.Models.FileMetadataDirectory[] GetFileMetadataDirectories(string file, IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.FileMetadataDirectory> results = [];
        IEnumerable<MetadataExtractor.Formats.FileSystem.FileMetadataDirectory> fileMetadataDirectories = directories.OfType<MetadataExtractor.Formats.FileSystem.FileMetadataDirectory>();
        foreach (MetadataExtractor.Formats.FileSystem.FileMetadataDirectory fileMetadataDirectory in fileMetadataDirectories)
        {
            if (fileMetadataDirectory.Tags.Count == 0)
                continue;
            DateTime? fileModifiedDate;
            string? fileName = fileMetadataDirectory.GetDescription(MetadataExtractor.Formats.FileSystem.FileMetadataDirectory.TagFileName);
            string? fileSize = fileMetadataDirectory.GetDescription(MetadataExtractor.Formats.FileSystem.FileMetadataDirectory.TagFileSize);
            if (fileMetadataDirectory.TryGetDateTime(MetadataExtractor.Formats.FileSystem.FileMetadataDirectory.TagFileModifiedDate, out DateTime checkDateTime))
                fileModifiedDate = checkDateTime;
            else
                fileModifiedDate = GetDateTime(fileMetadataDirectory.GetString(MetadataExtractor.Formats.FileSystem.FileMetadataDirectory.TagFileModifiedDate));
            if (fileName is null || !file.EndsWith(fileName))
                throw new NotSupportedException($"!{file}.EndsWith({fileName})");
            if (fileModifiedDate is null && fileName is null && fileSize is null)
                continue;
            results.Add(new(fileModifiedDate, fileName, fileSize));
        }
        return results.ToArray();
    }

    private static Shared.Models.GifHeaderDirectory[] GetGifHeaderDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.GifHeaderDirectory> results = [];
        IEnumerable<MetadataExtractor.Formats.Gif.GifHeaderDirectory> gifHeaderDirectories = directories.OfType<MetadataExtractor.Formats.Gif.GifHeaderDirectory>();
        foreach (MetadataExtractor.Formats.Gif.GifHeaderDirectory gifHeaderDirectory in gifHeaderDirectories)
        {
            if (gifHeaderDirectory.Tags.Count == 0)
                continue;
            string? imageHeight = gifHeaderDirectory.GetDescription(MetadataExtractor.Formats.Gif.GifHeaderDirectory.TagImageHeight);
            string? imageWidth = gifHeaderDirectory.GetDescription(MetadataExtractor.Formats.Gif.GifHeaderDirectory.TagImageWidth);
            if (imageHeight is null && imageWidth is null)
                continue;
            results.Add(new(imageHeight, imageWidth));
        }
        return results.ToArray();
    }

    private static Shared.Models.GpsDirectory[] GetGpsDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.GpsDirectory> results = [];
        IEnumerable<GpsDirectory> gpsDirectories = directories.OfType<GpsDirectory>();
        foreach (GpsDirectory gpsDirectory in gpsDirectories)
        {
            if (gpsDirectory.Tags.Count == 0)
                continue;
            DateTime? timeStamp;
            string? altitude = gpsDirectory.GetDescription(GpsDirectory.TagAltitude);
            string? latitude = gpsDirectory.GetDescription(GpsDirectory.TagLatitude);
            string? latitudeRef = gpsDirectory.GetDescription(GpsDirectory.TagLatitudeRef);
            string? longitude = gpsDirectory.GetDescription(GpsDirectory.TagLongitude);
            string? longitudeRef = gpsDirectory.GetDescription(GpsDirectory.TagLongitudeRef);
            if (gpsDirectory.TryGetDateTime(GpsDirectory.TagTimeStamp, out DateTime checkDateTime))
                timeStamp = checkDateTime;
            else
                timeStamp = GetDateTime(gpsDirectory.GetString(GpsDirectory.TagTimeStamp));
            if (altitude is null && latitude is null && latitudeRef is null && longitude is null && longitudeRef is null && timeStamp is null)
                continue;
            results.Add(new(altitude,
                            latitude,
                            latitudeRef,
                            longitude,
                            longitudeRef,
                            timeStamp));
        }
        return results.ToArray();
    }

    private static Shared.Models.JpegDirectory[] GetJpegDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.JpegDirectory> results = [];
        IEnumerable<MetadataExtractor.Formats.Jpeg.JpegDirectory> jpegDirectories = directories.OfType<MetadataExtractor.Formats.Jpeg.JpegDirectory>();
        foreach (MetadataExtractor.Formats.Jpeg.JpegDirectory jpegDirectory in jpegDirectories)
        {
            if (jpegDirectory.Tags.Count == 0)
                continue;
            string? imageHeight = jpegDirectory.GetDescription(MetadataExtractor.Formats.Jpeg.JpegDirectory.TagImageHeight);
            string? imageWidth = jpegDirectory.GetDescription(MetadataExtractor.Formats.Jpeg.JpegDirectory.TagImageWidth);
            if (imageHeight is null && imageWidth is null)
                continue;
            results.Add(new(imageHeight, imageWidth));
        }
        return results.ToArray();
    }

    private static Shared.Models.MakernoteDirectory[] GetMakernoteDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.MakernoteDirectory> results = [];
        IEnumerable<AppleMakernoteDirectory> appleMakernoteDirectories = directories.OfType<AppleMakernoteDirectory>();
        foreach (AppleMakernoteDirectory appleMakernoteDirectory in appleMakernoteDirectories)
        {
            if (appleMakernoteDirectory.Tags.Count == 0)
                continue;
            string? cameraSerialNumber = null;
            string? firmwareVersion = null;
            string? qualityAndFileFormat = null;
            if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
                continue;
            results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
        }
        IEnumerable<CanonMakernoteDirectory> canonMakernoteDirectories = directories.OfType<CanonMakernoteDirectory>();
        foreach (CanonMakernoteDirectory canonMakernoteDirectory in canonMakernoteDirectories)
        {
            if (canonMakernoteDirectory.Tags.Count == 0)
                continue;
            string? cameraSerialNumber = canonMakernoteDirectory.GetDescription(CanonMakernoteDirectory.TagModelId);
            string? firmwareVersion = canonMakernoteDirectory.GetDescription(CanonMakernoteDirectory.TagCanonFirmwareVersion);
            string? qualityAndFileFormat = canonMakernoteDirectory.GetDescription(CanonMakernoteDirectory.CameraSettings.TagQuality);
            if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
                continue;
            results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
        }
        IEnumerable<NikonType2MakernoteDirectory> nikonType2MakernoteDirectories = directories.OfType<NikonType2MakernoteDirectory>();
        foreach (NikonType2MakernoteDirectory nikonType2MakernoteDirectory in nikonType2MakernoteDirectories)
        {
            if (nikonType2MakernoteDirectory.Tags.Count == 0)
                continue;
            string? cameraSerialNumber = nikonType2MakernoteDirectory.GetDescription(NikonType2MakernoteDirectory.TagCameraSerialNumber);
            string? firmwareVersion = nikonType2MakernoteDirectory.GetDescription(NikonType2MakernoteDirectory.TagFirmwareVersion);
            string? qualityAndFileFormat = nikonType2MakernoteDirectory.GetDescription(NikonType2MakernoteDirectory.TagQualityAndFileFormat);
            if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
                continue;
            results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
        }
        IEnumerable<OlympusMakernoteDirectory> olympusMakernoteDirectories = directories.OfType<OlympusMakernoteDirectory>();
        foreach (OlympusMakernoteDirectory olympusMakernoteDirectory in olympusMakernoteDirectories)
        {
            if (olympusMakernoteDirectory.Tags.Count == 0)
                continue;
            string? cameraSerialNumber = olympusMakernoteDirectory.GetDescription(OlympusMakernoteDirectory.TagSerialNumber1);
            string? firmwareVersion = olympusMakernoteDirectory.GetDescription(OlympusMakernoteDirectory.TagBodyFirmwareVersion);
            string? qualityAndFileFormat = olympusMakernoteDirectory.GetDescription(OlympusMakernoteDirectory.TagJpegQuality);
            if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
                continue;
            results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
        }
        IEnumerable<PanasonicMakernoteDirectory> panasonicMakernoteDirectories = directories.OfType<PanasonicMakernoteDirectory>();
        foreach (PanasonicMakernoteDirectory panasonicMakernoteDirectory in panasonicMakernoteDirectories)
        {
            if (panasonicMakernoteDirectory.Tags.Count == 0)
                continue;
            string? cameraSerialNumber = panasonicMakernoteDirectory.GetDescription(PanasonicMakernoteDirectory.TagInternalSerialNumber);
            string? firmwareVersion = panasonicMakernoteDirectory.GetDescription(PanasonicMakernoteDirectory.TagFirmwareVersion);
            string? qualityAndFileFormat = panasonicMakernoteDirectory.GetDescription(PanasonicMakernoteDirectory.TagQualityMode);
            if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
                continue;
            results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
        }
        IEnumerable<SamsungType2MakernoteDirectory> samsungType2MakernoteDirectories = directories.OfType<SamsungType2MakernoteDirectory>();
        foreach (SamsungType2MakernoteDirectory samsungType2MakernoteDirectory in samsungType2MakernoteDirectories)
        {
            if (samsungType2MakernoteDirectory.Tags.Count == 0)
                continue;
            string? cameraSerialNumber = samsungType2MakernoteDirectory.GetDescription(SamsungType2MakernoteDirectory.TagSerialNumber);
            string? firmwareVersion = samsungType2MakernoteDirectory.GetDescription(SamsungType2MakernoteDirectory.TagFirmwareName);
            string? qualityAndFileFormat = null;
            if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
                continue;
            results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
        }
        IEnumerable<SonyType6MakernoteDirectory> sonyType6MakernoteDirectories = directories.OfType<SonyType6MakernoteDirectory>();
        foreach (SonyType6MakernoteDirectory sonyType6MakernoteDirectory in sonyType6MakernoteDirectories)
        {
            if (sonyType6MakernoteDirectory.Tags.Count == 0)
                continue;
            string? cameraSerialNumber = null;
            string? firmwareVersion = null;
            string? qualityAndFileFormat = null;
            if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
                continue;
            results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
        }
        return results.ToArray();
    }

    private static Shared.Models.PhotoshopDirectory[] GetPhotoshopDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.PhotoshopDirectory> results = [];
        IEnumerable<MetadataExtractor.Formats.Photoshop.PhotoshopDirectory> photoshopDirectories = directories.OfType<MetadataExtractor.Formats.Photoshop.PhotoshopDirectory>();
        foreach (MetadataExtractor.Formats.Photoshop.PhotoshopDirectory photoshopDirectory in photoshopDirectories)
        {
            if (photoshopDirectory.Tags.Count == 0)
                continue;
            string? jpegQuality = photoshopDirectory.GetDescription(MetadataExtractor.Formats.Photoshop.PhotoshopDirectory.TagJpegQuality);
            string? url = photoshopDirectory.GetDescription(MetadataExtractor.Formats.Photoshop.PhotoshopDirectory.TagUrl);
            if (jpegQuality is null && url is null)
                continue;
            results.Add(new(jpegQuality, url));
        }
        return results.ToArray();
    }

    private static Shared.Models.PngDirectory[] GetPngDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.PngDirectory> results = [];
        IEnumerable<MetadataExtractor.Formats.Png.PngDirectory> pngDirectories = directories.OfType<MetadataExtractor.Formats.Png.PngDirectory>();
        foreach (MetadataExtractor.Formats.Png.PngDirectory pngDirectory in pngDirectories)
        {
            if (pngDirectory.Tags.Count == 0)
                continue;
            string? imageHeight = pngDirectory.GetDescription(MetadataExtractor.Formats.Png.PngDirectory.TagImageHeight);
            string? imageWidth = pngDirectory.GetDescription(MetadataExtractor.Formats.Png.PngDirectory.TagImageWidth);
            string? textualData = pngDirectory.GetDescription(MetadataExtractor.Formats.Png.PngDirectory.TagTextualData);
            if (imageHeight is null && imageWidth is null && textualData is null)
                continue;
            results.Add(new(imageHeight, imageWidth, textualData));
        }
        return results.ToArray();
    }

    private static Shared.Models.QuickTimeMovieHeaderDirectory[] GetQuickTimeMovieHeaderDirectoryDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.QuickTimeMovieHeaderDirectory> results = [];
        IEnumerable<MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory> quickTimeMovieHeaderDirectories = directories.OfType<MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory>();
        foreach (MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory quickTimeMovieHeaderDirectory in quickTimeMovieHeaderDirectories)
        {
            if (quickTimeMovieHeaderDirectory.Tags.Count == 0)
                continue;
            DateTime? created;
            if (quickTimeMovieHeaderDirectory.TryGetDateTime(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated, out DateTime checkDateTime))
                created = checkDateTime;
            else
                created = GetDateTime(quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated));
            if (created is null)
                continue;
            results.Add(new(created));
        }
        return results.ToArray();
    }

    private static Shared.Models.QuickTimeTrackHeaderDirectory[] GetQuickTimeTrackHeaderDirectoryDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.QuickTimeTrackHeaderDirectory> results = [];
        IEnumerable<MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory> quickTimeTrackHeaderDirectories = directories.OfType<MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory>();
        foreach (MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory quickTimeTrackHeaderDirectory in quickTimeTrackHeaderDirectories)
        {
            if (quickTimeTrackHeaderDirectory.Tags.Count == 0)
                continue;
            DateTime? created;
            if (quickTimeTrackHeaderDirectory.TryGetDateTime(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated, out DateTime checkDateTime))
                created = checkDateTime;
            else
                created = GetDateTime(quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated));
            if (created is null)
                continue;
            results.Add(new(created));
        }
        return results.ToArray();
    }

    private static Shared.Models.WebPDirectory[] GetWebPDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        List<Shared.Models.WebPDirectory> results = [];
        IEnumerable<MetadataExtractor.Formats.WebP.WebPDirectory> webPDirectories = directories.OfType<MetadataExtractor.Formats.WebP.WebPDirectory>();
        foreach (MetadataExtractor.Formats.WebP.WebPDirectory webPDirectory in webPDirectories)
        {
            if (webPDirectory.Tags.Count == 0)
                continue;
            string? imageHeight = webPDirectory.GetDescription(MetadataExtractor.Formats.WebP.WebPDirectory.TagImageHeight);
            string? imageWidth = webPDirectory.GetDescription(MetadataExtractor.Formats.WebP.WebPDirectory.TagImageWidth);
            if (imageHeight is null && imageWidth is null)
                continue;
            results.Add(new(imageHeight, imageWidth));
        }
        return results.ToArray();
    }

    private static Shared.Models.ExifDirectory Covert(Shared.Models.FilePath filePath, Shared.Models.DeterministicHashCode deterministicHashCode, System.Drawing.Size? size, IReadOnlyList<MetadataExtractor.Directory> directories)
    {
        Shared.Models.ExifDirectory result;
        Shared.Models.AviDirectory[] aviDirectories = GetAviDirectories(directories);
        Shared.Models.GpsDirectory[] gpsDirectories = GetGpsDirectories(directories);
        Shared.Models.PngDirectory[] pngDirectories = GetPngDirectories(directories);
        Shared.Models.JpegDirectory[] jpegDirectories = GetJpegDirectories(directories);
        Shared.Models.WebPDirectory[] webPDirectories = GetWebPDirectories(directories);
        Shared.Models.ExifDirectoryBase[] exifBaseDirectories = GetExifBaseDirectories(directories);
        Shared.Models.GifHeaderDirectory[] gifHeaderDirectories = GetGifHeaderDirectories(directories);
        Shared.Models.MakernoteDirectory[] MakernoteDirectories = GetMakernoteDirectories(directories);
        Shared.Models.PhotoshopDirectory[] photoshopDirectories = GetPhotoshopDirectories(directories);
        Shared.Models.FileMetadataDirectory[] fileMetadataDirectories = GetFileMetadataDirectories(filePath.FullName, directories);
        Shared.Models.QuickTimeMovieHeaderDirectory[] quickTimeMovieHeaderDirectories = GetQuickTimeMovieHeaderDirectoryDirectories(directories);
        Shared.Models.QuickTimeTrackHeaderDirectory[] quickTimeTrackHeaderDirectories = GetQuickTimeTrackHeaderDirectoryDirectories(directories);
        result = new(aviDirectories,
                     exifBaseDirectories,
                     fileMetadataDirectories,
                     gifHeaderDirectories,
                     gpsDirectories,
                     size?.Height,
                     deterministicHashCode.Id ?? filePath.Id,
                     jpegDirectories,
                     MakernoteDirectories,
                     filePath.Name,
                     photoshopDirectories,
                     pngDirectories,
                     quickTimeMovieHeaderDirectories,
                     quickTimeTrackHeaderDirectories,
                     webPDirectories,
                     size?.Width);
        return result;
    }

    internal static Shared.Models.ExifDirectory GetExifDirectory(Shared.Models.FilePath filePath, Shared.Models.DeterministicHashCode deterministicHashCode)
    {
        Shared.Models.ExifDirectory? result;
        System.Drawing.Size? size = Dimensions.GetDimensions(filePath.FullName);
        IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName);
        result = Covert(filePath, deterministicHashCode, size, directories);
        return result;
    }

}