using System;
using System.Threading;
using System.Threading.Tasks;

using UnityEngine;


namespace AIRuntime.Runtime.Capabilities
{
    /// <summary>
    /// Logs capability failures while allowing cancellation
    /// to propagate as normal control flow.
    /// </summary>
    public sealed class ExceptionMiddleware :
        ICapabilityMiddleware
    {
        public async Task InvokeAsync(
            CapabilityContext context,
            CapabilityDelegate next)
        {
            try
            {
                await next(
                    context);
            }
            catch (OperationCanceledException)
            {
                // Cancellation is expected control flow.
                // Do not log it as an error.
                throw;
            }
            catch (Exception exception)
            {
                string message =
                    $"[Capability] '{context.Capability.Name}' failed: " +
                    exception.Message;

                if (exception is ValidationException &&
                    !IsWorkspaceSecurityViolation(
                        exception.Message))
                {
                    // Invalid tool arguments are returned to the agent so it
                    // can correct them. Keep the diagnostic visible without
                    // presenting expected recovery as a fatal runtime error.
                    Debug.LogWarning(
                        message);
                }
                else
                {
                    Debug.LogError(
                        message);
                }


                throw;
            }
        }


        private static bool IsWorkspaceSecurityViolation(
            string message)
        {
            if (string.IsNullOrWhiteSpace(message))
                return false;

            return message.IndexOf(
                       "escapes the workspace",
                       StringComparison.OrdinalIgnoreCase) >= 0 ||
                   message.IndexOf(
                       "must be relative to the workspace",
                       StringComparison.OrdinalIgnoreCase) >= 0 ||
                   message.IndexOf(
                       "contains a symbolic link or directory junction",
                       StringComparison.OrdinalIgnoreCase) >= 0;
        }
    }
}
