namespace ZB.MOM.WW.OtOpcUa.Cluster;

/// <summary>
///     Selects and configures the transport carrying central→node commands and node→central
///     deployment acks (per-cluster mesh Phase 2).
/// </summary>
/// <remarks>
///     <para>
///         <see cref="Mode"/> is a deliberate <b>dark switch</b>, not a permanent knob: both
///         transports live in the tree for one phase so the docker-dev rig can run the same
///         deployment over each and compare, and so a bad Phase 2 rolls back with a config change
///         rather than a revert. Phase 6 deletes the DistributedPubSub branch along with the single
///         mesh that made it viable.
///     </para>
///     <para>
///         <b>Discovery is deliberately asymmetric</b>, matching the sister project. Central
///         discovers nodes <i>from the database</i> — enabled, non-maintenance <c>ClusterNode</c>
///         rows, rebuilt every <see cref="ContactRefreshSeconds"/>. Nodes discover central <i>from
///         this section</i>: static, restart to change. The asymmetry follows the rate of change —
///         operators add and retire nodes, but central's own address is part of the deployment.
///     </para>
/// </remarks>
public sealed class MeshTransportOptions
{
    /// <summary>Configuration section name.</summary>
    public const string SectionName = "MeshTransport";

    /// <summary>Every command stays on DistributedPubSub — the pre-Phase-2 behaviour.</summary>
    public const string ModeDps = "Dps";

    /// <summary>Commands cross the ClusterClient receptionist boundary.</summary>
    public const string ModeClusterClient = "ClusterClient";

    /// <summary>
    ///     <see cref="ModeDps"/> (default) or <see cref="ModeClusterClient"/>. Any other value fails
    ///     the host at startup rather than silently falling back — a transport that is neither of
    ///     these delivers nothing, and the symptom would be commands that vanish.
    /// </summary>
    public string Mode { get; set; } = ModeDps;

    /// <summary>
    ///     Akka remoting addresses of the central nodes, e.g.
    ///     <c>akka.tcp://otopcua@central-1:4053</c>. <b>Node addresses only</b> — the
    ///     <c>/system/receptionist</c> path is appended at construction time.
    /// </summary>
    /// <remarks>
    ///     Each entry must be a <i>central</i> node's remoting endpoint, never this node's own port.
    ///     The sister project shipped a site template whose second contact was the site's own
    ///     remoting port; it is a permanent failure in the initial-contact rotation and stays
    ///     invisible until a command goes missing. <see cref="MeshTransportOptionsValidator"/>
    ///     rejects the malformed shapes at boot instead.
    /// </remarks>
    public string[] CentralContactPoints { get; set; } = [];

    /// <summary>
    ///     How often central re-reads <c>ClusterNode</c> rows to rebuild its contact points.
    ///     Refreshing on a timer (rather than only on admin change) means a row edited by any
    ///     process — migration, direct SQL, a second admin node — is picked up without a restart.
    /// </summary>
    public int ContactRefreshSeconds { get; set; } = 60;
}
