using Cronos;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Mirea.Api.Endpoint.Common.Attributes;
using Mirea.Api.Endpoint.Configuration.Model;
using System;
using System.Reflection;
using System.Threading.Tasks;

namespace Mirea.Api.Endpoint.Configuration.Core.Middleware;

public class CacheMaxAgeMiddleware(RequestDelegate next, IServiceProvider serviceProvider)
{
    public async Task InvokeAsync(HttpContext context)
    {
        if (!context.Response.StatusCode.ToString().StartsWith('2'))
        {
            await next(context);
            return;
        }

        var endpoint = context.GetEndpoint();

        var actionDescriptor = endpoint?.Metadata.GetMetadata<Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor>();

        if (actionDescriptor == null)
        {
            await next(context);
            return;
        }

        var controllerType = actionDescriptor.ControllerTypeInfo;
        var methodInfo = actionDescriptor.MethodInfo;

        var maxAgeAttribute = methodInfo.GetCustomAttribute<CacheMaxAgeAttribute>() ?? controllerType.GetCustomAttribute<CacheMaxAgeAttribute>();

        if (maxAgeAttribute == null)
        {
            await next(context);
            return;
        }

        switch (maxAgeAttribute.MaxAge)
        {
            case < 0:
                {
                    DateTime? nextDate;
                    var now = DateTime.UtcNow;

                    using (var scope = serviceProvider.CreateScope())
                    {
                        var updateCronString = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<GeneralConfig>>().Value.ScheduleSettings?.CronUpdateSchedule;

                        if (string.IsNullOrEmpty(updateCronString) ||
                            !CronExpression.TryParse(updateCronString, CronFormat.Standard, out var updateCron))
                        {
                            await next(context);
                            return;
                        }

                        nextDate = updateCron.GetNextOccurrence(now);
                    }

                    if (!nextDate.HasValue)
                    {
                        await next(context);
                        return;
                    }

                    context.Response.Headers.CacheControl = "max-age=" + (int)(nextDate.Value - now).TotalSeconds;
                    break;
                }
            case > 0:
                context.Response.Headers.CacheControl = "max-age=" + maxAgeAttribute.MaxAge;
                break;
        }

        await next(context);
    }
}