namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;

/// <summary>
/// Shared lax parsers for the multi-value Audit Log query parameters
/// (<c>channel</c>/<c>kind</c>/<c>status</c>/<c>site</c>). The Audit Log filter
/// wire-contract is consumed by three surfaces that MUST stay in lockstep:
/// <list type="bullet">
///   <item>the ManagementService <c>/api/audit/query</c> + <c>/api/audit/export</c>
///   endpoints,</item>
///   <item>the CentralUI <c>/api/centralui/audit/export</c> endpoint, and</item>
///   <item>the CentralUI <c>AuditLogPage</c> query-string drill-in parser.</item>
/// </list>
///
/// <para>
/// Each caller extracts the raw repeated values for a single parameter from its
/// own request type (ASP.NET <c>IQueryCollection</c>, a
/// <c>Dictionary&lt;string, StringValues&gt;</c> from <c>QueryHelpers.ParseQuery</c>,
/// etc.) and passes them here as a plain <see cref="IEnumerable{T}"/> of strings —
/// so this helper carries NO ASP.NET / <c>Microsoft.Extensions.Primitives</c>
/// dependency and can live in <c>ZB.MOM.WW.ScadaBridge.Commons</c>.
/// </para>
///
/// <para>
/// <b>Lax-parse contract.</b> Every value of a repeated parameter is parsed
/// independently; an unparseable or blank element is silently dropped (NO 400)
/// rather than failing the whole set. An empty result collapses to <c>null</c> so
/// the corresponding filter dimension stays unconstrained.
/// </para>
/// </summary>
public static class AuditQueryParamParsers
{
    /// <summary>
    /// Parses each raw value as <typeparamref name="TEnum"/> (case-insensitive),
    /// dropping unparseable values silently. Returns <c>null</c> when
    /// <paramref name="rawValues"/> is <c>null</c>, empty, or yields no parseable
    /// value — so the filter dimension stays unconstrained.
    /// </summary>
    /// <typeparam name="TEnum">The enum type to parse each raw value into.</typeparam>
    /// <param name="rawValues">Raw query-parameter string values to parse; may be null.</param>
    /// <returns>A non-empty list of parsed values, or <c>null</c> if no values could be parsed.</returns>
    public static IReadOnlyList<TEnum>? ParseEnumList<TEnum>(IEnumerable<string?>? rawValues)
        where TEnum : struct, Enum
    {
        if (rawValues is null)
        {
            return null;
        }

        var parsed = new List<TEnum>();
        foreach (var raw in rawValues)
        {
            if (Enum.TryParse<TEnum>(raw, ignoreCase: true, out var value))
            {
                parsed.Add(value);
            }
        }
        return parsed.Count > 0 ? parsed : null;
    }

    /// <summary>
    /// Trims each raw value and drops blank entries. Returns <c>null</c> when
    /// <paramref name="rawValues"/> is <c>null</c>, empty, or every value was
    /// blank.
    /// </summary>
    /// <param name="rawValues">Raw query-parameter string values to trim and filter; may be null.</param>
    /// <returns>A non-empty list of trimmed strings, or <c>null</c> if no non-blank values remain.</returns>
    public static IReadOnlyList<string>? ParseStringList(IEnumerable<string?>? rawValues)
    {
        if (rawValues is null)
        {
            return null;
        }

        var parsed = new List<string>();
        foreach (var raw in rawValues)
        {
            if (!string.IsNullOrWhiteSpace(raw))
            {
                parsed.Add(raw.Trim());
            }
        }
        return parsed.Count > 0 ? parsed : null;
    }
}
