namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS;

/// <summary>
///     Parsed FOCAS target address — IP + TCP port. Canonical <c>focas://{ip}[:{port}]</c>.
///     Default port 8193 (Fanuc-reserved FOCAS Ethernet port).
/// </summary>
public sealed record FocasHostAddress(string Host, int Port)
{
    /// <summary>Fanuc-reserved TCP port for FOCAS Ethernet.</summary>
    public const int DefaultPort = 8193;

    /// <inheritdoc />
    public override string ToString() => Port == DefaultPort
        ? $"focas://{Host}"
        : $"focas://{Host}:{Port}";

    /// <summary>Attempts to parse a FOCAS address string.</summary>
    /// <param name="value">The address string to parse.</param>
    /// <returns>A parsed address, or null if the string is invalid.</returns>
    public static FocasHostAddress? TryParse(string? value)
    {
        if (string.IsNullOrWhiteSpace(value)) return null;
        const string prefix = "focas://";

        // Canonical form is focas://{ip}[:{port}], but the AdminUI persists the device host as a
        // scheme-less "{ip}[:{port}]" (e.g. "10.201.31.5:8193"). Accept that too: take the body
        // after focas:// when present, else the whole value when it carries NO other URI scheme
        // (a "://" that isn't ours — e.g. http:// — is still rejected). The host-contains-colon
        // guard below then rejects malformed scheme typos like "focas:10.0.0.5:8193".
        string body;
        if (value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
            body = value[prefix.Length..];
        else if (!value.Contains("://", StringComparison.Ordinal))
            body = value;
        else
            return null;
        if (string.IsNullOrEmpty(body)) return null;

        var colonIdx = body.LastIndexOf(':');
        string host;
        var port = DefaultPort;
        if (colonIdx >= 0)
        {
            host = body[..colonIdx];
            if (!int.TryParse(body[(colonIdx + 1)..], out port) || port is <= 0 or > 65535)
                return null;
        }
        else
        {
            host = body;
        }
        // Empty host, or a host still carrying a colon (e.g. the malformed "focas:10.0.0.5" left
        // when someone wrote "focas:10.0.0.5:8193" without the //), is invalid.
        if (string.IsNullOrEmpty(host) || host.Contains(':', StringComparison.Ordinal)) return null;
        return new FocasHostAddress(host, port);
    }
}
