using System.Collections.Generic;
using System.Threading.Tasks;

using AIRuntime.Runtime.Capabilities;
using AIRuntime.Runtime.Capabilities.Permissions;
using AIRuntime.Runtime.Filesystem.Models;


namespace AIRuntime.Runtime.Filesystem
{
    /// <summary>
    /// Lists entries in a workspace directory.
    /// </summary>
    public sealed class ListDirectoryCapability
        : CapabilityBase<ListDirectoryArguments>
    {
        public override string Name =>
            "list_directory";


        public override string Description =>
            "Lists immediate entries in one directory. Set entryType to Files or Directories when requested. Set outputFormat to PathsOnly for exact path-list answers; otherwise Metadata returns compact entry details. Unity .meta sidecars are omitted unless includeMetaFiles is explicitly true. Use this only for root, top-level, or other non-recursive requests; use list_directory_tree for 'all folders in the project', nested, or recursive requests.";


        public override CapabilityPermission Permission =>
            CapabilityPermission.ReadOnly;


        protected override async Task<object> ExecuteAsync(
            ListDirectoryArguments args,
            CapabilityContext context)
        {
            context.CancellationToken
                .ThrowIfCancellationRequested();


            IReadOnlyList<string> names =
                await context.FileSystem.ListDirectoryAsync(
                    args.Path);


            List<DirectoryEntryModel> entries =
                new List<DirectoryEntryModel>();


            foreach (
                string name
                in names)
            {
                context.CancellationToken
                    .ThrowIfCancellationRequested();


                FileInfoModel info =
                    await context.FileSystem.GetFileInfoAsync(
                        CombinePath(
                            args.Path,
                            name));


                if (info.Exists &&
                    (args.IncludeMetaFiles ||
                     info.IsDirectory ||
                     !info.Name.EndsWith(
                         ".meta",
                         System.StringComparison.OrdinalIgnoreCase)) &&
                    ShouldInclude(
                        info,
                        args.EntryType))
                {
                    entries.Add(
                        new DirectoryEntryModel
                        {
                            Path =
                                info.Path,

                            Name =
                                info.Name,

                            Extension =
                                info.Extension,

                            Size =
                                info.Size,

                            IsDirectory =
                                info.IsDirectory,

                            IsSymbolicLink =
                                info.IsSymbolicLink
                        });
                }
            }


            context.CancellationToken
                .ThrowIfCancellationRequested();

            if (args.OutputFormat ==
                DirectoryEntryOutputFormat.PathsOnly)
            {
                List<string> paths =
                    new List<string>();

                foreach (
                    DirectoryEntryModel entry
                    in entries)
                {
                    paths.Add(
                        entry.Path);
                }

                return paths;
            }

            return entries;
        }


        private static bool ShouldInclude(
            FileInfoModel info,
            DirectoryEntryFilter filter)
        {
            switch (filter)
            {
                case DirectoryEntryFilter.All:
                    return true;

                case DirectoryEntryFilter.Files:
                    return !info.IsDirectory;

                case DirectoryEntryFilter.Directories:
                    return info.IsDirectory;

                default:
                    return false;
            }
        }


        private static string CombinePath(
            string parent,
            string child)
        {
            string normalizedParent =
                (parent ??
                 string.Empty)
                .Trim()
                .Replace(
                    '\\',
                    '/')
                .TrimEnd(
                    '/');


            if (string.IsNullOrEmpty(
                    normalizedParent) ||
                normalizedParent == ".")
            {
                return child;
            }


            return normalizedParent +
                   "/" +
                   child;
        }
    }
}
