namespace StellaOps.Feedser.Source.Common.Url;

/// <summary>
/// Utilities for normalizing URLs from upstream feeds.
/// </summary>
public static class UrlNormalizer
{
    /// <summary>
    /// Attempts to normalize <paramref name="value"/> relative to <paramref name="baseUri"/>.
    /// Removes fragments and enforces HTTPS when possible.
    /// </summary>
    public static bool TryNormalize(string? value, Uri? baseUri, out Uri? normalized, bool stripFragment = true, bool forceHttps = false)
    {
        normalized = null;
        if (string.IsNullOrWhiteSpace(value))
        {
            return false;
        }

        if (!Uri.TryCreate(value.Trim(), UriKind.RelativeOrAbsolute, out var candidate))
        {
            return false;
        }

        if (!candidate.IsAbsoluteUri)
        {
            if (baseUri is null)
            {
                return false;
            }

            if (!Uri.TryCreate(baseUri, candidate, out candidate))
            {
                return false;
            }
        }

        if (forceHttps && string.Equals(candidate.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
        {
            candidate = new UriBuilder(candidate) { Scheme = Uri.UriSchemeHttps, Port = candidate.IsDefaultPort ? -1 : candidate.Port }.Uri;
        }

        if (stripFragment && !string.IsNullOrEmpty(candidate.Fragment))
        {
            var builder = new UriBuilder(candidate) { Fragment = string.Empty };
            candidate = builder.Uri;
        }

        normalized = candidate;
        return true;
    }

    public static Uri NormalizeOrThrow(string value, Uri? baseUri = null, bool stripFragment = true, bool forceHttps = false)
    {
        if (!TryNormalize(value, baseUri, out var normalized, stripFragment, forceHttps) || normalized is null)
        {
            throw new FormatException($"Value '{value}' is not a valid URI");
        }

        return normalized;
    }
}
