namespace Mbproxy.Bcd;

/// <summary>
/// Immutable description of a single BCD-encoded V-memory tag as seen on the Modbus wire.
/// Width is 16 (one register) or 32 (two registers, CDAB low-word-first).
///
/// <para><b><see cref="CacheTtlMs"/></b> is the resolved per-tag response-cache TTL in
/// milliseconds. 0 (the default) means caching is disabled for this tag. Positive values
/// cap upstream staleness; the multi-tag-range read uses <c>min(TTLs)</c> across all
/// matched tags and treats any 0 in the range as "uncached for the whole read."</para>
/// </summary>
public sealed record BcdTag(ushort Address, byte Width, int CacheTtlMs = 0)
{
    /// <summary>
    /// Creates a <see cref="BcdTag"/> and validates that Width is 16 or 32.
    /// </summary>
    /// <exception cref="ArgumentException">Width is not 16 or 32.</exception>
    public static BcdTag Create(ushort address, byte width, int cacheTtlMs = 0)
    {
        if (width != 16 && width != 32)
            throw new ArgumentException(
                $"BCD tag Width must be 16 or 32; got {width} at address {address}.",
                nameof(width));

        if (cacheTtlMs < 0)
            throw new ArgumentException(
                $"BCD tag CacheTtlMs must be >= 0; got {cacheTtlMs} at address {address}.",
                nameof(cacheTtlMs));

        return new BcdTag(address, width, cacheTtlMs);
    }

    /// <summary>True when this tag occupies two registers (32-bit BCD).</summary>
    public bool IsThirtyTwoBit => Width == 32;

    /// <summary>True when this tag opts into the response cache.</summary>
    public bool IsCacheable => CacheTtlMs > 0;

    /// <summary>
    /// The address of the high-word register for a 32-bit tag (Address + 1).
    /// Only valid when <see cref="IsThirtyTwoBit"/> is true.
    /// </summary>
    /// <exception cref="InvalidOperationException">Tag is 16-bit.</exception>
    public ushort HighRegister =>
        IsThirtyTwoBit
            ? (ushort)(Address + 1)
            : throw new InvalidOperationException(
                $"HighRegister is only defined for 32-bit BCD tags (Address {Address} is {Width}-bit).");
}
