// Copyright 2020-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Adapted from server/websocket.go in the NATS server Go source.

using ZB.MOM.NatsNet.Server.Internal;

namespace ZB.MOM.NatsNet.Server.WebSocket;

/// <summary>
/// Per-connection WebSocket read state.
/// Mirrors Go <c>wsReadInfo</c> struct in server/websocket.go.
/// </summary>
internal sealed class WsReadInfo
{
    /// <summary>Whether masking is disabled for this connection (e.g. leaf node).</summary>
    public bool     NoMasking   { get; set; }

    /// <summary>Whether per-message deflate compression is active.</summary>
    public bool     Compressed  { get; set; }

    /// <summary>The current frame opcode.</summary>
    public WsOpCode FrameType   { get; set; }

    /// <summary>Number of payload bytes remaining in the current frame.</summary>
    public int      PayloadLeft { get; set; }

    /// <summary>The 4-byte masking key (only valid when masking is active).</summary>
    public int[]    Mask        { get; set; } = new int[4];

    /// <summary>Current offset into <see cref="Mask"/>.</summary>
    public int      MaskOffset  { get; set; }

    /// <summary>Accumulated compressed payload buffers awaiting decompression.</summary>
    public byte[]?  Compress    { get; set; }

    public WsReadInfo() { }
}

/// <summary>
/// Server-level WebSocket state, shared across all WebSocket connections.
/// Mirrors Go <c>srvWebsocket</c> struct in server/websocket.go.
/// Replaces the stub in NatsServerTypes.cs.
/// </summary>
internal sealed class SrvWebsocket
{
    /// <summary>
    /// Tracks WebSocket connect URLs per server (ref-counted).
    /// Mirrors Go <c>connectURLsMap refCountedUrlSet</c>.
    /// </summary>
    public RefCountedUrlSet ConnectUrlsMap { get; set; } = new();

    /// <summary>
    /// TLS configuration for the WebSocket listener.
    /// Mirrors Go <c>tls bool</c> field (true if TLS is required).
    /// </summary>
    public System.Net.Security.SslServerAuthenticationOptions? TlsConfig { get; set; }

    /// <summary>Whether per-message deflate compression is enabled globally.</summary>
    public bool Compression { get; set; }

    /// <summary>Host the WebSocket server is listening on.</summary>
    public string Host { get; set; } = string.Empty;

    /// <summary>Port the WebSocket server is listening on (may be ephemeral).</summary>
    public int Port { get; set; }
}

/// <summary>
/// Handles WebSocket upgrade and framing for a single connection.
/// Mirrors the WebSocket-related methods on Go <c>client</c> in server/websocket.go.
/// Full implementation is deferred to session 23.
/// </summary>
internal sealed class WebSocketHandler
{
    private readonly NatsServer _server;

    public WebSocketHandler(NatsServer server)
    {
        _server = server;
    }

    /// <summary>Upgrades an HTTP connection to WebSocket protocol.</summary>
    public void UpgradeToWebSocket(
        System.IO.Stream stream,
        System.Net.Http.Headers.HttpRequestHeaders headers)
        => throw new NotImplementedException("TODO: session 23 — websocket");

    /// <summary>Parses a WebSocket frame from the given buffer slice.</summary>
    public void ParseFrame(byte[] data, int offset, int count)
        => throw new NotImplementedException("TODO: session 23 — websocket");

    /// <summary>Writes a WebSocket frame with the given payload.</summary>
    public void WriteFrame(WsOpCode opCode, byte[] payload, bool final, bool compress)
        => throw new NotImplementedException("TODO: session 23 — websocket");

    /// <summary>Writes a WebSocket close frame with the given status code and reason.</summary>
    public void WriteCloseFrame(int statusCode, string reason)
        => throw new NotImplementedException("TODO: session 23 — websocket");
}
