using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Enumeration;

namespace ExtensiblePortfolioSite.SDK.Resources.VFS
{
    /// <summary>
    /// Represents a VFS Entry Type/Kind
    /// </summary>
    public enum VirtualEntryKind
    {
        /// <summary>
        /// <see cref="IVirtualFile"/>
        /// </summary>
        File,
        /// <summary>
        /// <see cref="IVirtualFolder"/>
        /// </summary>
        Folder
    }
    /// <summary>
    /// Represents a VFS Entry
    /// </summary>
    public interface IVirtualEntry
    {
        /// <summary>
        /// VFS Entry Kind
        /// </summary>
        public VirtualEntryKind Kind { get; }

        /// <summary>
        /// Entry Name
        /// </summary>
        public String Name { get; }

        /// <summary>
        /// Delete the VFS Entry
        /// </summary>
        public void Delete();
    }

    /// <summary>
    /// Represents a VFS File
    /// </summary>
    public interface IVirtualFile : IVirtualEntry
    {
        VirtualEntryKind IVirtualEntry.Kind => VirtualEntryKind.File;

        String IVirtualEntry.Name => Filename;

        /// <summary>
        /// Folder Containing This File
        /// </summary>
        public IVirtualFolder Folder { get; }

        /// <summary>
        /// File Name
        /// </summary>
        public String Filename { get; }

        /// <summary>
        /// Open the File Stream
        /// </summary>
        /// <returns></returns>
        public Stream OpenStream();
    }

    /// <summary>
    /// Represents a VFS Folder
    /// </summary>
    public interface IVirtualFolder : IVirtualEntry
    {
        VirtualEntryKind IVirtualEntry.Kind => VirtualEntryKind.Folder;
        String IVirtualEntry.Name => Foldername;

        /// <summary>
        /// The Parent Folder
        /// </summary>
        IVirtualFolder? Parent { get; }

        /// <summary>
        /// File Name
        /// </summary>
        public String Foldername { get; }

        /// <summary>
        /// Create a File with the Given <paramref name="Filename"/>
        /// </summary>
        /// <param name="Filename">File Name</param>
        /// <param name="File">Underlying Resource File</param>
        /// <returns>new VFS File Entry</returns>
        IVirtualFile CreateFile(String Filename, IResource File);

        /// <summary>
        /// Create a SubFolder with the Given <paramref name="Foldername"/>
        /// </summary>
        /// <param name="Foldername">Folder Name</param>
        /// <returns>new VFS Folder Entry</returns>
        IVirtualFolder CreateFolder(String Foldername);

        /// <summary>
        /// Attempts to get the specified File
        /// </summary>
        /// <param name="Filename">File Name</param>
        /// <returns>Virtual File or Null</returns>
        /// <exception cref="InvalidOperationException"/>
        IVirtualFile? GetFile(String Filename)
        {
            IVirtualEntry? entry = GetEntry(Filename);
            return entry is IVirtualFile file
                ? file
                : entry == null
                    ? null
                    : throw new InvalidOperationException($"{Filename} is not a file!");
        }

        /// <summary>
        /// Attempts to get the specified Folder
        /// </summary>
        /// <param name="Foldername">Folder Name</param>
        /// <returns>Virtual Folder or Null</returns>
        /// <exception cref="InvalidOperationException"/>
        IVirtualFolder? GetFolder(String Foldername)
        {
            IVirtualEntry? entry = GetEntry(Foldername);
            return entry is IVirtualFolder folder
                ? folder
                : entry == null
                    ? null
                    : throw new InvalidOperationException($"{Foldername} is not a folder!");
        }

        /// <summary>
        /// Get a Specified Entry by Name
        /// </summary>
        /// <param name="Entry">Entry Name</param>
        /// <returns>Entry or Null</returns>
        IVirtualEntry? GetEntry(String Entry);

        /// <summary>
        /// Delete the Specified Entry
        /// </summary>
        /// <param name="Entry">Entry name</param>
        void Delete(String Entry);

        /// <summary>
        /// Enumerate all Entries within this Folder
        /// </summary>
        IEnumerable<IVirtualEntry> EnumerateEntries();
    }
}
