using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Aurora.Backend.Utils
{
    public class FileSystemUtils
    {

        public FileSystemUtils()
        {
        }


        /// <summary>
        /// Asynchronousely recursively traverse a directory path.
        /// </summary>
        /// <param name="path">The path to the directory to traverse</param>
        /// <param name="extensions">Comma separated list of file extensions to accept</param>
        public static List<FileInfo> TraverseFoldersAsync(string path, string extensions)
        {
            string[] extensionList = extensions.Split(',');

            ConcurrentBag<Task> tasks = new ConcurrentBag<Task>();
            List<FileInfo> outFiles = new List<FileInfo>();
            DirectoryInfo directoryInfo = new DirectoryInfo(path);

            tasks.Add(Task.Run(() => Traverse(directoryInfo, tasks, outFiles, extensionList)));

            Task waitingTask;
            while (tasks.TryTake(out waitingTask))
            {
                waitingTask.Wait();
            }

            return outFiles;
        }



        /// <summary>
        /// Recursive method to capture children of a directory.
        /// </summary>
        /// <param name="dir">The directory to traverse</param>
        /// <param name="tasks">The list of currently running tasks</param>
        private static void Traverse(DirectoryInfo dir, ConcurrentBag<Task> tasks, List<FileInfo> outFiles, string[] extensions)
        {
            try
            {
                DirectoryInfo[] directoryInfos = dir.GetDirectories();
                //Enque children
                foreach (DirectoryInfo childInfo in directoryInfos)
                {
                    tasks.Add(Task.Run(() => Traverse(childInfo, tasks, outFiles, extensions)));
                }

                //Collect files
                foreach (FileInfo fileInfo in dir.GetFiles())
                {
                    if (extensions.Any(e => e == fileInfo.Extension))
                    {
                        //Don't know if this lock is necessary
                        lock (outFiles)
                        {
                            outFiles.Add(fileInfo);
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"{ex.GetType()} {ex.Message}\n{ex.StackTrace}");
                ex = ex.InnerException;
            }
        }

    }
}