namespace MemberCenter.Infrastructure.Configuration;

public static class ReturnUrlValidator
{
    public static bool IsAllowedExternal(Uri candidate, IEnumerable<string?> allowedValues, bool allowInsecureHttp) =>
        allowedValues.Any(value => IsWithinAllowedPrefix(candidate, value, allowInsecureHttp));

    public static bool IsWithinAllowedPrefix(Uri candidate, string? allowedValue, bool allowInsecureHttp)
    {
        if (string.IsNullOrWhiteSpace(allowedValue) ||
            !Uri.TryCreate(allowedValue, UriKind.Absolute, out var allowed) ||
            !IsHttpScheme(allowed.Scheme) ||
            !string.IsNullOrEmpty(allowed.UserInfo) ||
            !string.IsNullOrEmpty(allowed.Query) ||
            !string.IsNullOrEmpty(allowed.Fragment))
        {
            return false;
        }

        if (!allowInsecureHttp && (candidate.Scheme != Uri.UriSchemeHttps || allowed.Scheme != Uri.UriSchemeHttps))
        {
            return false;
        }

        if (!IsHttpScheme(candidate.Scheme) ||
            !string.IsNullOrEmpty(candidate.UserInfo) ||
            !string.Equals(candidate.Scheme, allowed.Scheme, StringComparison.OrdinalIgnoreCase) ||
            !string.Equals(candidate.IdnHost, allowed.IdnHost, StringComparison.OrdinalIgnoreCase) ||
            candidate.Port != allowed.Port)
        {
            return false;
        }

        var allowedPath = allowed.AbsolutePath.TrimEnd('/');
        return string.IsNullOrEmpty(allowedPath) ||
            string.Equals(candidate.AbsolutePath, allowedPath, StringComparison.Ordinal) ||
            candidate.AbsolutePath.StartsWith($"{allowedPath}/", StringComparison.Ordinal);
    }

    private static bool IsHttpScheme(string scheme) =>
        string.Equals(scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) ||
        string.Equals(scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase);
}
