using System.Globalization;
using System.Text;

namespace View_by_Distance.Shared.Models.Stateless;

internal abstract class XDate
{

    internal static (int Season, string seasonName) GetSeason(int dayOfYear)
    {
        (int Season, string seasonName) result = dayOfYear switch
        {
            < 78 => new(0, "Winter"),
            < 171 => new(1, "Spring"),
            < 264 => new(2, "Summer"),
            < 354 => new(3, "Fall"),
            _ => new(4, "Winter")
        };
        return result;
    }

    internal static (bool?, string[]) IsWrongYear(string[] segments, string year)
    {
        bool? result;
        string[] results = (
            from l
            in segments
            where l?.Length > 2
            && (
                l[..2] is "18" or "19" or "20"
            || (l.Length == 5 && l.Substring(1, 2) is "18" or "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#'))
            || (l.Length == 6 && l[..2] is "18" or "19" or "20" && l[4] == '.')
            || (l.Length == 7 && l.Substring(1, 2) is "18" or "19" or "20" && l[5] == '.')
            )
            select l
        ).ToArray();
        string[] matches = (
            from l
            in results
            where l == year
            || (l.Length == 5 && l.Substring(1, 4) == year && (l[0] is '~' or '=' or '-' or '^' or '#'))
            || (l.Length == 6 && l[..4] == year && l[4] == '.')
            || (l.Length == 7 && l.Substring(1, 4) == year && l[5] == '.')
            select l
        ).ToArray();
        if (results.Length == 0)
            result = null;
        else
            result = matches.Length == 0;
        return new(result, results);
    }

    internal static DateTime? GetDateTimeOriginal(ExifDirectory exifDirectory)
    {
        DateTime? result;
        List<DateTime> results = [];
        if (exifDirectory.ExifDirectoryBase.DateTimeOriginal is not null)
            results.Add(exifDirectory.ExifDirectoryBase.DateTimeOriginal.Value);
        if (exifDirectory.AviDirectory.DateTimeOriginal is not null)
            results.Add(exifDirectory.AviDirectory.DateTimeOriginal.Value);
        if (exifDirectory.QuickTimeMovieHeaderDirectory.Created is not null)
            results.Add(exifDirectory.QuickTimeMovieHeaderDirectory.Created.Value);
        if (exifDirectory.QuickTimeTrackHeaderDirectory.Created is not null)
            results.Add(exifDirectory.QuickTimeTrackHeaderDirectory.Created.Value);
        result = results.Count == 0 ? null : results.Min();
        return result;
    }

    private static DateTime? GetDateTimeFromName(string fileNameWithoutExtension)
    {
        DateTime? result = null;
        int length;
        string format;
        string fullFormat;
        StringBuilder value = new();
        const string ticksExample = "##################";
        string[][] dateFormats =
        [
            [string.Empty, "yyyyMMdd_HHmmss", string.Empty],
            [string.Empty, "yyyyMMddHHmmssfff", string.Empty],
            [string.Empty, "yyyyMMdd_", ticksExample],
            [string.Empty, "yyyy-MM-dd_", ticksExample],
            [string.Empty, "yyyy-MM-dd.", ticksExample],
            // [string.Empty, "yyyy-MM-dd.", $"{ticksExample}.{fileHolder.Length}"],
            [string.Empty, "yyyy-MM-dd HH.mm.ss", string.Empty],
            [string.Empty, "yyyyMMdd_HHmmss", "_LLS"],
            [string.Empty, "yyyyMMdd_HHmmss", "_HDR"],
            ["WIN_", "yyyyMMdd_HH_mm_ss", "_Pro"],
            ["IMG_", "yyyyMMdd_HHmmss", string.Empty],
            ["IMG#####-", "yyyyMMdd-HHmm", string.Empty],
            ["CameraZOOM-", "yyyyMMddHHmmss", string.Empty],
            ["VideoCapture_", "yyyyMMdd-HHmmss ", string.Empty]
        ];
        foreach (string[] dateFormat in dateFormats)
        {
            _ = value.Clear();
            if (dateFormat.Length != 3)
                throw new Exception();
            fullFormat = string.Join(string.Empty, dateFormat);
            if (fileNameWithoutExtension.Length != fullFormat.Length)
                continue;
            format = dateFormat[1];
            length = dateFormat[0].Length + dateFormat[1].Length;
            for (int i = dateFormat[0].Length; i < length; i++)
                _ = value.Append(fileNameWithoutExtension[i]);
            if (value.Length != format.Length)
                continue;
            if (DateTime.TryParseExact(value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime checkDateTime))
            {
                if (fileNameWithoutExtension.Length < ticksExample.Length || !long.TryParse(fileNameWithoutExtension[^ticksExample.Length..], out long ticks))
                    result = checkDateTime;
                else
                    result = new DateTime(ticks);
                break;
            }
        }
        return result;
    }

    internal static DateTime GetMinimum(ExifDirectory exifDirectory)
    {
        DateTime result;
        List<DateTime> results = [];
        if (exifDirectory.ExifDirectoryBase.DateTimeOriginal is not null)
            results.Add(exifDirectory.ExifDirectoryBase.DateTimeOriginal.Value);
        if (exifDirectory.AviDirectory.DateTimeOriginal is not null)
            results.Add(exifDirectory.AviDirectory.DateTimeOriginal.Value);
        if (exifDirectory.QuickTimeMovieHeaderDirectory.Created is not null)
            results.Add(exifDirectory.QuickTimeMovieHeaderDirectory.Created.Value);
        if (exifDirectory.QuickTimeTrackHeaderDirectory.Created is not null)
            results.Add(exifDirectory.QuickTimeTrackHeaderDirectory.Created.Value);
        if (results.Count == 0)
        {
            string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(exifDirectory.OriginalFileName);
            DateTime? dateTime = GetDateTimeFromName(fileNameWithoutExtension);
            if (dateTime is not null)
                results.Add(dateTime.Value);
            if (exifDirectory.ExifDirectoryBase.DateTime is not null)
                results.Add(exifDirectory.ExifDirectoryBase.DateTime.Value);
            if (exifDirectory.ExifDirectoryBase.DateTimeDigitized is not null)
                results.Add(exifDirectory.ExifDirectoryBase.DateTimeDigitized.Value);
        }
        if (results.Count == 0 && exifDirectory.FileMetadataDirectory.FileModifiedDate is not null)
            results.Add(exifDirectory.FileMetadataDirectory.FileModifiedDate.Value);
        result = results.Count == 0 ? DateTime.MinValue : results.Min();
        return result;
    }

}