using ZB.MOM.WW.OtOpcUa.Driver.AbCip;

namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests;

/// <summary>
///     Per-family marker for the <c>ab_server</c> Docker compose profile a given test
///     targets. The compose file (<c>Docker/docker-compose.yml</c>) is the canonical
///     source of truth for which tags a family seeds + which <c>--plc</c> mode the
///     simulator boots in; this record just ties a family enum to operator-facing
///     notes so fixture + test code can filter / branch by family.
/// </summary>
/// <param name="Family">OtOpcUa driver family this profile targets.</param>
/// <param name="ComposeProfile">The <c>docker compose --profile</c> name that brings
///     this family's ab_server up. Matches the service key in the compose file.</param>
/// <param name="Notes">Operator-facing description of coverage + any quirks.</param>
public sealed record AbServerProfile(
    AbCipPlcFamily Family,
    string ComposeProfile,
    string Notes)
{
    /// <summary>Default ab_server port — matches the compose-file port-map + the
    /// CIP / EtherNet/IP standard.</summary>
    public const int DefaultPort = 44818;
}

/// <summary>Canonical profiles covering every AB CIP family shipped in PRs 9–12.</summary>
public static class KnownProfiles
{
    /// <summary>Gets all known server profiles.</summary>
    /// <remarks>Expression-bodied (evaluated on access) so it observes the
    /// <c>static readonly</c> profile fields below after they are initialised;
    /// a <c>{ get; } =</c> initialiser here runs in textual order — before those
    /// fields — and would capture an all-null list.</remarks>
    public static IReadOnlyList<AbServerProfile> All =>
        [ControlLogix, CompactLogix, Micro800, GuardLogix];

    /// <summary>Gets the ControlLogix profile.</summary>
    public static readonly AbServerProfile ControlLogix = new(
        Family: AbCipPlcFamily.ControlLogix,
        ComposeProfile: "controllogix",
        Notes: "Widest-coverage profile — PR 9 baseline. UDTs unit-tested via golden Template Object buffers; ab_server lacks full UDT emulation.");

    /// <summary>Gets the CompactLogix profile.</summary>
    public static readonly AbServerProfile CompactLogix = new(
        Family: AbCipPlcFamily.CompactLogix,
        ComposeProfile: "compactlogix",
        Notes: "ab_server doesn't enforce the narrower ConnectionSize; driver-side profile caps it per PR 10.");

    /// <summary>Gets the Micro800 profile.</summary>
    public static readonly AbServerProfile Micro800 = new(
        Family: AbCipPlcFamily.Micro800,
        ComposeProfile: "micro800",
        Notes: "--plc=Micro800 mode (unconnected-only, empty path). Driver-side enforcement verified in the unit suite.");

    /// <summary>Gets the GuardLogix profile.</summary>
    public static readonly AbServerProfile GuardLogix = new(
        Family: AbCipPlcFamily.GuardLogix,
        ComposeProfile: "guardlogix",
        Notes: "ab_server has no safety subsystem — _S-suffixed seed tag triggers driver-side ViewOnly classification only.");

    /// <summary>Gets the profile for a specific family.</summary>
    /// <param name="family">The AB CIP PLC family.</param>
    /// <returns>The corresponding server profile.</returns>
    public static AbServerProfile ForFamily(AbCipPlcFamily family) =>
        All.FirstOrDefault(p => p.Family == family)
        ?? throw new ArgumentOutOfRangeException(nameof(family), family, "No integration profile for this family.");
}
