namespace MyOffice.Web.Infrastructure.Attributes;

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ModelBinding;

[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class DefaultFromBodyAttribute : Attribute
{
}

public class DefaultFromBodyBindingConvention : IActionModelConvention
{
	public void Apply(ActionModel action)
	{
		if (action == null)
		{
			throw new ArgumentNullException(nameof(action));
		}

		if (action.Controller.Attributes.Any(x => x is DefaultFromBodyAttribute))
		{
			foreach (var parameter in action.Parameters)
			{
				if (parameter.Attributes.Any(x =>
					    x is FromQueryAttribute
					    or FromRouteAttribute
					    or FromHeaderAttribute
					    or FromFormAttribute
					    or FromServicesAttribute))
				{
					continue;
				}

				// Already bound (e.g. CancellationToken → Special) — do not force Body.
				if (parameter.BindingInfo?.BindingSource is { } existing
				    && existing != BindingSource.ModelBinding
				    && existing != BindingSource.Custom)
				{
					continue;
				}

				var paramType = parameter.ParameterInfo.ParameterType;
				if (paramType == typeof(CancellationToken)
				    || Nullable.GetUnderlyingType(paramType) == typeof(CancellationToken))
				{
					continue;
				}

				var isSimpleType = paramType.IsPrimitive
					|| paramType.IsEnum
					|| paramType == typeof(string)
					|| paramType == typeof(decimal)
					|| paramType == typeof(Guid)
					|| paramType == typeof(Guid?)
					|| paramType == typeof(DateTime)
					|| paramType == typeof(DateTime?)
					|| paramType == typeof(DateOnly)
					|| paramType == typeof(DateOnly?)
					|| paramType == typeof(TimeOnly)
					|| paramType == typeof(TimeOnly?);

				if (!isSimpleType)
				{
					parameter.BindingInfo ??= new BindingInfo();
					parameter.BindingInfo.BindingSource = BindingSource.Body;
				}
			}
		}
	}
}
