using Microsoft.AspNetCore.Components;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;

namespace ZB.MOM.WW.ScadaBridge.CentralUI.Components.Health;

/// <summary>
/// Site Call Audit code-behind for <see cref="SiteCallKpiTiles"/>.
/// Renders three KPI tiles — Buffered, Stuck, Parked — from a
/// <see cref="SiteCallKpiResponse"/> the parent Health dashboard supplies.
/// Tiles act as drill-in links: clicking navigates to <c>/site-calls/report</c>
/// with the relevant query-string filter pre-applied. Mirrors
/// <see cref="AuditKpiTiles"/> and the Notification Outbox KPI section on the
/// Health dashboard.
/// </summary>
/// <remarks>
/// <para>
/// <b>Why purely presentational.</b> The Health dashboard already owns a 10s
/// auto-refresh loop; pushing that into the tile component would either
/// duplicate it (one timer per tile) or awkwardly couple back to the page. The
/// parent passes a fresh <see cref="SiteCallKpiResponse"/> every refresh and the
/// tile component re-renders. This is the same contract <see cref="AuditKpiTiles"/>
/// follows.
/// </para>
/// <para>
/// <b>Snapshot shape.</b> Unlike <see cref="AuditKpiTiles"/> — which takes a
/// dedicated <c>AuditLogKpiSnapshot</c> type — Site Call KPIs travel in the
/// <see cref="SiteCallKpiResponse"/> message itself (it carries the KPI fields
/// directly), so that record doubles as the snapshot here. <see cref="IsAvailable"/>
/// is a separate flag rather than the record's own <c>Success</c> so the parent
/// can also surface a transport failure (an Ask that threw) as unavailable.
/// </para>
/// <para>
/// <b>Threshold borders.</b> Mirrors the Notification Outbox tile pattern: the
/// Parked tile gets a danger border when <c>ParkedCount &gt; 0</c>; the Stuck
/// tile gets a warning border when <c>StuckCount &gt; 0</c>. Buffered is a plain
/// count tile with no threshold colour — a non-zero buffer is normal operation.
/// </para>
/// </remarks>
public partial class SiteCallKpiTiles
{
    /// <summary>
    /// Latest KPI snapshot. <c>null</c> means the parent has not loaded it yet
    /// or the load failed — the tiles render em dashes in that case.
    /// </summary>
    [Parameter] public SiteCallKpiResponse? Snapshot { get; set; }

    /// <summary>
    /// True when <see cref="Snapshot"/> is a successful query result. False when
    /// the parent's refresh threw, or the response itself reported a fault, and
    /// the displayed values should be rendered as em dashes with an error
    /// explanation underneath.
    /// </summary>
    [Parameter] public bool IsAvailable { get; set; }

    /// <summary>
    /// Optional error message to render underneath the tiles when
    /// <see cref="IsAvailable"/> is false. Mirrors how the Notification Outbox
    /// section on the Health dashboard surfaces transient KPI failures.
    /// </summary>
    [Parameter] public string? ErrorMessage { get; set; }

    /// <summary>
    /// Optional per-node KPI breakdown.
    /// When non-null and non-empty, a compact node-level stuck/parked sub-table
    /// is rendered below the main tiles. <c>null</c> means the parent has not
    /// loaded it yet or has opted out — the sub-table is suppressed entirely.
    /// </summary>
    [Parameter] public IReadOnlyList<SiteCallNodeKpiSnapshot>? PerNodeSnapshots { get; set; }

    /// <summary>
    /// True when <see cref="PerNodeSnapshots"/> is a successful query result.
    /// Used to suppress the sub-table on a load failure.
    /// </summary>
    [Parameter] public bool PerNodeAvailable { get; set; }

    /// <summary>Whether the per-node sub-table has data to render.</summary>
    internal bool HasNodeBreakdown =>
        PerNodeAvailable && PerNodeSnapshots is { Count: > 0 };

    // ── Buffered tile ───────────────────────────────────────────────────────

    private string BufferedDisplay =>
        IsAvailable && Snapshot is not null
            ? Snapshot.BufferedCount.ToString("N0")
            : "—";

    private void NavigateToBuffered()
    {
        // Buffered is "everything still in flight" — no single status maps to
        // it, so the natural drill-in is the unfiltered Site Calls report sorted
        // by newest, mirroring how the Audit volume/backlog tiles drop the
        // operator on the unfiltered Audit Log grid.
        Navigation.NavigateTo("/site-calls/report");
    }

    // ── Stuck tile ──────────────────────────────────────────────────────────

    private string StuckDisplay =>
        IsAvailable && Snapshot is not null
            ? Snapshot.StuckCount.ToString("N0")
            : "—";

    // Stuck above zero is a warning signal — cached calls that have been
    // Pending/Retrying past the stuck-age threshold. Matches the Notification
    // Outbox Stuck tile (border-warning when StuckCount > 0).
    private string StuckBorderClass =>
        IsAvailable && Snapshot is not null && Snapshot.StuckCount > 0
            ? "border-warning"
            : string.Empty;

    private string StuckTextClass =>
        IsAvailable && Snapshot is not null && Snapshot.StuckCount > 0
            ? "text-warning"
            : string.Empty;

    private void NavigateToStuck()
    {
        // Drill in with the report's "stuck only" filter pre-applied.
        Navigation.NavigateTo("/site-calls/report?stuck=true");
    }

    // ── Parked tile ─────────────────────────────────────────────────────────

    private string ParkedDisplay =>
        IsAvailable && Snapshot is not null
            ? Snapshot.ParkedCount.ToString("N0")
            : "—";

    // Parked above zero is a danger signal — cached calls that exhausted retries
    // and need an operator Retry/Discard. Matches the Notification Outbox Parked
    // tile (border-danger when ParkedCount > 0).
    private string ParkedBorderClass =>
        IsAvailable && Snapshot is not null && Snapshot.ParkedCount > 0
            ? "border-danger"
            : string.Empty;

    private string ParkedTextClass =>
        IsAvailable && Snapshot is not null && Snapshot.ParkedCount > 0
            ? "text-danger"
            : string.Empty;

    private void NavigateToParked()
    {
        // Drill in pre-filtered to Parked — the report's Status filter accepts
        // ?status=Parked and Parked rows carry the Retry/Discard relay actions.
        Navigation.NavigateTo("/site-calls/report?status=Parked");
    }
}
