using System.Globalization;
using System.Linq;

namespace QRRapidoApp.Middleware
{
    /// <summary>
    /// Middleware de redirecionamento de idioma otimizado para SEO.
    ///
    /// Comportamento:
    /// - "/" → Retorna 200 OK em Português (canonical)
    /// - "/pt-BR" ou "/pt-BR/*" → Redireciona 301 para "/" ou "/*" (sem prefixo)
    /// - "/es" ou "/es/*" → Retorna 200 OK em Espanhol (mantém URL)
    /// - "/en" ou "/en/*" → Retorna 200 OK em Inglês (mantém URL)
    /// - "/pix", "/wifi", etc. → Retorna 200 OK em Português (sem redirect)
    /// </summary>
    public class LanguageRedirectionMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<LanguageRedirectionMiddleware> _logger;
        private readonly string[] _supportedCultures = { "pt-BR", "es", "en" };
        private const string DefaultCulture = "pt-BR";
        private const string CookieName = ".AspNetCore.Culture";

        public LanguageRedirectionMiddleware(RequestDelegate next, ILogger<LanguageRedirectionMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            var pathString = context.Request.Path.Value ?? "";

            // Skip API routes immediately using the raw path
            if (pathString.StartsWith("/api", StringComparison.OrdinalIgnoreCase))
            {
                await _next(context);
                return;
            }

            // Skip redirection for non-GET requests (POST/PUT/PATCH/DELETE).
            // A 301 redirect converts POST to GET, breaking form submissions.
            // Language canonicalization only matters for crawlers (GET).
            if (!HttpMethods.IsGet(context.Request.Method) && !HttpMethods.IsHead(context.Request.Method))
            {
                await _next(context);
                return;
            }

            var path = pathString.TrimStart('/') ?? "";

            // Skip other special routes
            if (IsSpecialRoute(path))
            {
                await _next(context);
                return;
            }

            var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
            var firstSegment = segments.Length > 0 ? segments[0] : "";

            // Check if URL starts with a culture segment (supported or unsupported)
            if (IsCultureLikeSegment(firstSegment))
            {
                // Supported: pt-BR (Default/Canonical)
                if (string.Equals(firstSegment, "pt-BR", StringComparison.OrdinalIgnoreCase))
                {
                    RedirectToCanonical(context, segments);
                    return;
                }

                // Supported: es (Spanish neutral)
                if (string.Equals(firstSegment, "es", StringComparison.OrdinalIgnoreCase))
                {
                    SetCulture(context, "es");
                    await _next(context);
                    return;
                }

                // Supported: en (English)
                if (string.Equals(firstSegment, "en", StringComparison.OrdinalIgnoreCase))
                {
                    SetCulture(context, "en");
                    await _next(context);
                    return;
                }

                // Handle aliases or unsupported cultures (e.g. /en-US/, /pt/)
                if (TryHandleCultureAliasOrUnknown(context, firstSegment, segments))
                {
                    return;
                }
            }

            // No culture prefix or unknown segment -> Serve in Portuguese (default)
            SetCulture(context, DefaultCulture);
            await _next(context);
        }

        private bool IsCultureLikeSegment(string segment)
        {
            if (string.IsNullOrEmpty(segment)) return false;

            // Matches xx (like en, pt, es) or xx-XX (like pt-BR, en-US)
            return segment.Length == 2 || (segment.Length == 5 && segment[2] == '-');
        }

        private bool TryHandleCultureAliasOrUnknown(HttpContext context, string firstSegment, string[] segments)
        {
            // Map known aliases to canonical forms
            if (string.Equals(firstSegment, "es-py", StringComparison.OrdinalIgnoreCase))
                return RedirectToLanguage(context, "es", segments);

            if (string.Equals(firstSegment, "en-us", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(firstSegment, "en-gb", StringComparison.OrdinalIgnoreCase))
                return RedirectToLanguage(context, "en", segments);

            // For anything else that looks like a culture (pt, fr, de, etc.)
            // redirect to the canonical Portuguese URL (no prefix).
            return RedirectToCanonical(context, segments);
        }

        private bool RedirectToLanguage(HttpContext context, string culture, string[] segments)
        {
            var remainingPath = segments.Length > 1
                ? "/" + string.Join('/', segments.Skip(1))
                : "";

            var redirectUrl = "/" + culture + remainingPath;
            return ExecuteRedirect(context, redirectUrl);
        }

        private bool RedirectToCanonical(HttpContext context, string[] segments)
        {
            var remainingPath = segments.Length > 1
                ? "/" + string.Join('/', segments.Skip(1))
                : "/";

            return ExecuteRedirect(context, remainingPath);
        }

        private bool ExecuteRedirect(HttpContext context, string url)
        {
            if (context.Request.QueryString.HasValue)
            {
                url += context.Request.QueryString.Value;
            }

            _logger.LogInformation("SEO Redirect: {Source} -> {Dest}", context.Request.Path, url);
            context.Response.Redirect(url, permanent: true);
            return true;
        }

        private void SetCulture(HttpContext context, string culture)
        {
            var cultureInfo = new CultureInfo(culture);
            CultureInfo.CurrentCulture = cultureInfo;
            CultureInfo.CurrentUICulture = cultureInfo;
            context.Items["Culture"] = culture;
        }

        private bool IsSpecialRoute(string path)
        {
            var specialRoutes = new[]
            {
                "api/", "health", "_framework/", "lib/", "css/", "js/", "images/",
                "favicon.ico", "robots.txt", "sitemap.xml", "ads.txt",
                "signin-", "signout-", "Account/", "Pagamento/", "Home/Error"
            };

            return specialRoutes.Any(route => path.StartsWith(route, StringComparison.OrdinalIgnoreCase));
        }
    }
}
