using System.Net;
using Newtonsoft.Json;
using Npgsql;

namespace Fast.Shared.Database.Models;

public class NpgsqlErrorHandlerMiddleware(RequestDelegate next)
{

    public async Task Invoke(HttpContext context)
    {
        const string retryKey = "NpgsqlErrorHandler.RetryCount";

        try
        {
            await next(context);
        }
        catch (InvalidCastException ex) when (ex.Message.Contains("DataTypeName '-'"))
        {
            // Check if we've already retried this request to prevent infinite loops
            if (context.Items.TryGetValue(retryKey, out var retryCountObj) && retryCountObj is int retryCount && retryCount > 0)
            {
                // We've already tried once, don't retry again
                Console.WriteLine("Npgsql error persisted after retry. Returning 503.");

                string errorMessage = "Database connection error. Please try again in a moment.";
                var result = JsonConvert.SerializeObject(errorMessage);

                if (!context.Response.HasStarted)
                {
                    context.Response.ContentType = "application/json";
                    context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
                    await context.Response.WriteAsync(result);
                }
                return;
            }

            // This error occurs when the database was overwritten while the app was running.
            // Npgsql caches type mappings that become stale after a database restore.
            // We must completely drop the old DataSource and create a new one to force reloading types.
            ProgramShared.ResetDatabaseConnection();

            // Also clear global pools just in case
            NpgsqlConnection.ClearAllPools();
            Console.WriteLine("Reset Npgsql DataSource and cleared pools. Retrying request...");

            // Mark that we've attempted a retry
            context.Items[retryKey] = 1;

            // Retry the request with fresh connection pools
            try
            {
                await next(context);
            }
            catch (InvalidCastException retryEx) when (retryEx.Message.Contains("DataTypeName '-'"))
            {
                Console.WriteLine("Npgsql error persisted after retry. Returning 503.");

                string errorMessage = "Database connection error. Please refresh the page.";
                var result = JsonConvert.SerializeObject(errorMessage);

                if (!context.Response.HasStarted)
                {
                    context.Response.ContentType = "application/json";
                    context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
                    await context.Response.WriteAsync(result);
                }
            }
        }
    }
}
