using System.Threading.Tasks;

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


namespace AIRuntime.Runtime.Filesystem
{
    /// <summary>
    /// Writes UTF-8 text to a file in the current workspace.
    /// </summary>
    public sealed class WriteFileCapability
        : CapabilityBase<WriteFileArguments>
    {
        public override string Name =>
            "write_file";


        public override string Description =>
            "Writes UTF-8 text to a file in the current workspace. " +
            "Missing directories are created automatically.";


        public override CapabilityPermission Permission =>
            CapabilityPermission.Write;


        protected override async Task<object> ExecuteAsync(
            WriteFileArguments args,
            CapabilityContext context)
        {
            AtomicFileWriteResult result;
            if (context.FileSystem is IAtomicFileSystem atomic)
            {
                result = await atomic.WriteFileAtomicallyAsync(
                    args.Path,
                    args.Content,
                    args.ExpectedSha256,
                    args.ExpectedAbsent,
                    args.AllowOverwrite);
            }
            else
            {
                bool existed = await context.FileSystem.FileExistsAsync(args.Path);
                if (args.ExpectedAbsent && existed)
                    throw new System.IO.IOException($"File '{args.Path}' already exists; ExpectedAbsent was true.");
                if (!string.IsNullOrWhiteSpace(args.ExpectedSha256))
                    throw new System.NotSupportedException("This filesystem does not support hash-guarded atomic writes.");
                if (existed && !args.AllowOverwrite)
                    throw new System.IO.IOException($"File '{args.Path}' already exists and overwrite was not authorized.");
                await context.FileSystem.WriteFileAsync(args.Path, args.Content);
                result = new AtomicFileWriteResult
                {
                    Created = !existed,
                    Replaced = existed,
                    PreviousSha256 = string.Empty,
                    CurrentSha256 = string.Empty,
                    CurrentLength = (args.Content ?? string.Empty).Length
                };
            }

            return new
            {
                Succeeded = true,
                args.Path,
                result.Created,
                result.Replaced,
                result.PreviousSha256,
                result.CurrentSha256,
                result.PreviousLength,
                result.CurrentLength,
                Atomic = context.FileSystem is IAtomicFileSystem
            };
        }
    }
}
