using Microsoft.Data.Sqlite;

namespace ZB.MOM.WW.OtOpcUa.Core.AlarmHistorian;

/// <summary>
///     DDL for the Part 9 scripted-alarm condition state: one row per alarm identity holding the
///     operator-supplied state (Enabled / Acked / Confirmed / Shelving) plus the ack/confirm audit
///     trail and comment history.
/// </summary>
/// <remarks>
///     <para>
///         Replaces the central config DB's <c>ScriptedAlarmState</c> table as the node-local home
///         for this state (per-cluster mesh Phase 4, which cuts the ConfigDb from driver-only
///         nodes). Living in the consolidated LocalDb file is what lets the state replicate to the
///         redundant pair peer, exactly like the alarm store-and-forward buffer — see
///         <see cref="AlarmSfSchema"/>, which this mirrors.
///     </para>
///     <para>
///         Deliberately depends on nothing but <see cref="SqliteConnection"/> so it can be applied
///         to any connection — the host's <c>LocalDbSetup.OnReady</c> in production, and a bare
///         connection in a test — without dragging the DI graph along.
///     </para>
///     <para>
///         <b>The primary key is the alarm identity, and Save is an unconditional upsert onto it.</b>
///         Convergence across the pair is last-writer-wins over the primary key, handled by the
///         LocalDb replication HLC — so the store stacks no application-level last-write-wins on top,
///         the same discipline the alarm-sf sink and the deployment pointer follow.
///     </para>
///     <para>
///         <b>ActiveState has no column</b> — it is re-derived from the live predicate on startup,
///         so persisting it would only risk operators seeing a stale Active on restart. Likewise
///         <c>LastActiveUtc</c> / <c>LastClearedUtc</c> re-derive alongside it and get no columns.
///         <c>LastTransitionUtc</c> is carried by <c>updated_at_utc</c> — the row-write timestamp is
///         the last transition. Timestamps are round-trip ("O") TEXT so lexicographic order is
///         chronological; nullable timestamps and audit fields are stored as NULL.
///     </para>
/// </remarks>
public static class AlarmConditionStateSchema
{
    /// <summary>Table holding one condition-state row per scripted-alarm identity.</summary>
    public const string StateTable = "alarm_condition_state";

    /// <summary>
    ///     Creates the state table if it does not already exist. Idempotent.
    /// </summary>
    /// <param name="connection">
    ///     An already-open connection. <c>ILocalDb.CreateConnection()</c> hands out open,
    ///     pragma-configured connections — do not call <c>Open()</c> on one.
    /// </param>
    public static void Apply(SqliteConnection connection)
    {
        ArgumentNullException.ThrowIfNull(connection);

        using var cmd = connection.CreateCommand();

        // The four *_state columns are always written to a mapped, non-null string (Enabled/Disabled,
        // Acknowledged/Unacknowledged, Confirmed/Unconfirmed, Unshelved/OneShotShelved/TimedShelved),
        // so they are NOT NULL. comments_json is never null either — an empty trail is the literal
        // "[]". The audit user/comment/utc columns and shelving_expires_utc are NULL when the alarm
        // has no such history yet. updated_at_utc carries LastTransitionUtc (there is no dedicated
        // transition column).
        cmd.CommandText = """
            CREATE TABLE IF NOT EXISTS alarm_condition_state (
                scripted_alarm_id    TEXT NOT NULL PRIMARY KEY,
                enabled_state        TEXT NOT NULL,
                acked_state          TEXT NOT NULL,
                confirmed_state      TEXT NOT NULL,
                shelving_state       TEXT NOT NULL,
                shelving_expires_utc TEXT NULL,
                last_ack_user        TEXT NULL,
                last_ack_comment     TEXT NULL,
                last_ack_utc         TEXT NULL,
                last_confirm_user    TEXT NULL,
                last_confirm_comment TEXT NULL,
                last_confirm_utc     TEXT NULL,
                comments_json        TEXT NOT NULL,
                updated_at_utc       TEXT NOT NULL
            );
            """;
        cmd.ExecuteNonQuery();
    }
}
