using System.Reflection;
using Fw.Utility.UnifyResponse;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;

namespace XF.Domain.Filters
{
    public class UnifyResponseFilter : IActionFilter
    {
        /// <summary>
        /// Called before the action executes, after model binding is complete.
        /// </summary>
        /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext" />.</param>
        public void OnActionExecuting(ActionExecutingContext context)
        {
        }

        /// <summary>
        /// Called after the action executes, before the action result.
        /// </summary>
        /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Mvc.Filters.ActionExecutedContext" />.</param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Canceled || context.Exception != null)
            {
                return;
            }

            // if (context.ActionDescriptor is ControllerActionDescriptor action)
            // {
            //     var origin = action?.MethodInfo.GetCustomAttribute(typeof(OriginResponseAttribute));
            //     if (origin is not null) return;    
            // }

            switch (context.Result)
            {
                case JsonResult jsonResult:
                    if (jsonResult.Value is not null && jsonResult.Value is not ApiResponse)
                    {
                        jsonResult.Value = ApiResponse<object>.Success(jsonResult.Value);
                    }

                    return;
                case BadRequestResult _:
                case OkResult _:
                case FileResult _:
                    context.HttpContext.Response.Headers.TryAdd("Access-Control-Expose-Headers", "Content-Disposition");
                    break;
                case StatusCodeResult _:
                case BadRequestObjectResult _:
                    // do nothing
                    return;
                case ObjectResult objectResult:
                    if (objectResult.Value is OpenResponse rsp)
                    {
                        context.Result = new OkObjectResult(rsp.Value);
                        break;
                    }

                    if (objectResult.Value is ApiResponse) break;
                    context.Result = new JsonResult(objectResult.Value == null
                        ? new ApiResponse()
                        : ApiResponse<object>.Success(objectResult.Value));
                    break;
                case EmptyResult _:
                    context.Result = new JsonResult(new ApiResponse());
                    return;
            }
        }
    }
}