using Harmonia.Core.Engine;
using Harmonia.Core.Imaging;
using Harmonia.Core.Models;
using Harmonia.Core.Tags;

namespace Harmonia.Core.Scanner;

public class AudioFileScanner(IAudioEngine audioEngine, ITagResolver tagResolver, IAudioImageExtractor audioImageExtractor) : IAudioFileScanner
{
    public async Task<Song[]> GetSongsAsync(string[] fileNames, CancellationToken cancellationToken)
    {
        List<Song> songs = [];

        foreach (string fileName in fileNames)
        {
            if (string.IsNullOrWhiteSpace(fileName) || File.Exists(fileName) == false)
                continue;

            Song? song = await GetSongAsync(fileName, cancellationToken);

            if (song == null)
                continue;

            songs.Add(song);
        }

        return [.. songs];
    }

    private async Task<Song> GetSongAsync(string fileName, CancellationToken cancellationToken)
    {
        FileInfo fileInfo = new(fileName);
        SongTagInfo songTagInfo = tagResolver.GetSongTagInfo(fileName);
        //using SongPictureInfo? songPictureInfo = audioImageExtractor.ExtractImage(fileName, songTagInfo);
        SongPictureInfo? songPictureInfo = await audioImageExtractor.ExtractImageAsync(fileName, songTagInfo, cancellationToken);

        Song song = new()
        {
            FileName = fileName,
            Size = (ulong)fileInfo.Length,
            LastModified = fileInfo.LastWriteTime,
            Title = songTagInfo.Title,
            Album = songTagInfo.Album,
            Artists = songTagInfo.Artists,
            AlbumArtists = songTagInfo.AlbumArtists,
            DiscNumber = songTagInfo.DiscNumber,
            TrackNumber = songTagInfo.TrackNumber,
            Length = songTagInfo.Length,
            Year = songTagInfo.Year,
            Genre = songTagInfo.Genre,
            BitRate = songTagInfo.BitRate,
            SampleRate = songTagInfo.SampleRate,
            ImageName = songPictureInfo?.ImageName,
            ImageHash = songPictureInfo?.ImageHash
        };

        return song;
    }

    public async Task<Song[]> GetSongsFromPathAsync(string path, CancellationToken cancellationToken)
    {
        FileInfo[] fileInfoList = GetAllFilesFromDirectory(path);
        string[] fileNames = [.. fileInfoList.Select(x => x.FullName).OrderBy(x => x)];

        return await GetSongsAsync(fileNames, cancellationToken);
    }

    private FileInfo[] GetAllFilesFromDirectory(string directoryName)
    {
        DirectoryInfo directoryInfo = new(directoryName);

        if (directoryInfo.Exists == false)
            return [];

        List<FileInfo> fileInfoList = [];

        var directories = directoryInfo.GetDirectories().Where(x => x.Attributes.HasFlag(FileAttributes.Hidden) == false);

        var extensions = audioEngine.SupportedFormats.Select(x => x.Replace("*.", ".").ToLower()).ToList();
        var files = directoryInfo.EnumerateFiles("*.*", SearchOption.AllDirectories).Where(x => x.Attributes.HasFlag(FileAttributes.Hidden) == false);
        var songFiles = files.Where(x => extensions.Contains(x.Extension.ToLower())).OrderBy(x => x.Name);

        foreach (FileInfo fileInfo in songFiles)
            fileInfoList.Add(fileInfo);

        return [.. fileInfoList];
    }
}