using ZB.MOM.WW.MxGateway.Contracts.Proto;

namespace ZB.MOM.WW.MxGateway.Server.Dashboard;

/// <summary>
///     One active-alarm row as shown on the dashboard Alarms tab. Projected
///     from an <see cref="ActiveAlarmSnapshot"/> so the Razor component never
///     touches protobuf types directly.
/// </summary>
public sealed record DashboardActiveAlarm(
    string Reference,
    string Provider,
    string Area,
    string Source,
    string AlarmType,
    int Severity,
    AlarmConditionState State,
    DateTimeOffset? LastTransition,
    string OperatorUser,
    string OperatorComment,
    string Description)
{
    /// <summary>Projects a worker active-alarm snapshot into a dashboard alarm row.</summary>
    /// <param name="snapshot">The snapshot returned by <c>QueryActiveAlarms</c>.</param>
    /// <returns>The projected dashboard alarm.</returns>
    public static DashboardActiveAlarm FromSnapshot(ActiveAlarmSnapshot snapshot)
    {
        ArgumentNullException.ThrowIfNull(snapshot);

        string provider = string.Empty;
        string reference = snapshot.AlarmFullReference ?? string.Empty;
        int bang = reference.IndexOf('!', StringComparison.Ordinal);
        if (bang > 0)
        {
            provider = reference[..bang];
        }

        return new DashboardActiveAlarm(
            Reference: reference,
            Provider: provider,
            Area: snapshot.Category ?? string.Empty,
            Source: snapshot.SourceObjectReference ?? string.Empty,
            AlarmType: snapshot.AlarmTypeName ?? string.Empty,
            Severity: snapshot.Severity,
            State: snapshot.CurrentState,
            LastTransition: snapshot.LastTransitionTimestamp?.ToDateTimeOffset(),
            OperatorUser: snapshot.OperatorUser ?? string.Empty,
            OperatorComment: snapshot.OperatorComment ?? string.Empty,
            Description: snapshot.Description ?? string.Empty);
    }

    /// <summary>True when this alarm is active and not yet acknowledged.</summary>
    public bool IsUnacknowledged => State == AlarmConditionState.Active;
}

/// <summary>Result of a dashboard active-alarm query.</summary>
/// <param name="Alarms">The active alarms, or an empty list on error.</param>
/// <param name="Error">A diagnostic message when the query failed; otherwise null.</param>
/// <param name="WorkerProcessId">The worker process id backing the dashboard session, when available.</param>
/// <param name="SnapshotTruncated">
///     True when the provider fetch behind <paramref name="Alarms"/> hit its per-fetch cap, so the
///     list may be missing active alarms. Distinct from <paramref name="Error"/>: the query
///     succeeded and every row shown is real — only the set's completeness is in doubt, which the
///     page states as a caveat rather than a failure.
/// </param>
public sealed record DashboardAlarmQueryResult(
    IReadOnlyList<DashboardActiveAlarm> Alarms,
    string? Error,
    int? WorkerProcessId,
    bool SnapshotTruncated = false);
