#if os(macOS)
import CryptoKit
import Foundation
import Network

/// T-iOS-9 test infra (owned by `URLSessionTermTransportTests`): a minimal
/// SCRIPTED WebSocket server over raw TCP on 127.0.0.1 with an ephemeral port.
/// macOS-only by design — the SessionCore suite runs via `swift test` on
/// macOS (plan §7 T-iOS-9); real-Node-server coverage is T-iOS-16.
///
/// Deliberately raw TCP + hand-rolled RFC 6455 framing instead of
/// `NWProtocolWebSocket`, because the tests must:
///  (a) read the HTTP upgrade request verbatim (Origin header assertion —
///      `NWProtocolWebSocket` hides the request headers),
///  (b) inject binary frames, oversize frames, close frames, and abrupt TCP
///      termination — exactly the failure modes T-iOS-9 must classify.
///
/// Test infra is inherently stateful I/O plumbing; all mutable state is
/// NSLock-protected and the type is `@unchecked Sendable` under that
/// discipline (mirrors the production adapter's documented approach).
final class ScriptedWSServer: @unchecked Sendable {

    /// One recorded HTTP upgrade request.
    struct Upgrade: Sendable {
        /// e.g. `GET /term HTTP/1.1`.
        let requestLine: String
        /// Header names lowercased; values trimmed.
        let headers: [String: String]
    }

    /// RFC 6455 wire constants (named — no magic numbers).
    private enum Wire {
        static let finBit: UInt8 = 0x80
        static let opcodeMask: UInt8 = 0x0F
        static let maskBit: UInt8 = 0x80
        static let payloadLenMask: UInt8 = 0x7F
        static let len16Marker = 126
        static let len64Marker = 127
        static let maxTinyPayload = 125
        static let maskKeyLength = 4
        static let opcodeText: UInt8 = 0x1
        static let opcodeBinary: UInt8 = 0x2
        static let opcodeClose: UInt8 = 0x8
        static let opcodePing: UInt8 = 0x9
        static let opcodePong: UInt8 = 0xA
        /// RFC 6455 §1.3 Sec-WebSocket-Accept magic GUID.
        static let acceptGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
        static let headerTerminator: [UInt8] = [0x0D, 0x0A, 0x0D, 0x0A] // \r\n\r\n
        static let receiveChunkLimit = 1 << 16
    }

    /// Upgrade requests, one per accepted client handshake (buffered stream —
    /// yields before consumption are never lost). Single consumer per test.
    let upgrades: AsyncStream<Upgrade>
    /// Text frames received FROM the client, unmasked, in arrival order.
    let clientTextFrames: AsyncStream<String>

    private let upgradesContinuation: AsyncStream<Upgrade>.Continuation
    private let clientTextContinuation: AsyncStream<String>.Continuation
    private let queue = DispatchQueue(label: "ScriptedWSServer")
    private let lock = NSLock()
    private var listener: NWListener?
    private var connection: NWConnection?
    private var rxBuffer = [UInt8]()
    private var isHandshakeDone = false
    private var startContinuation: CheckedContinuation<UInt16, any Error>?
    private var stopContinuation: CheckedContinuation<Void, Never>?

    init() {
        (upgrades, upgradesContinuation) = AsyncStream<Upgrade>.makeStream()
        (clientTextFrames, clientTextContinuation) = AsyncStream<String>.makeStream()
    }

    // MARK: - Lifecycle

    /// Bind 127.0.0.1 on a system-assigned port; returns the port once ready.
    func start() async throws -> UInt16 {
        let parameters = NWParameters.tcp
        parameters.requiredLocalEndpoint = NWEndpoint.hostPort(
            host: NWEndpoint.Host("127.0.0.1"), port: .any
        )
        let listener = try NWListener(using: parameters)
        lock.withLock { self.listener = listener }
        listener.newConnectionHandler = { [weak self] in self?.adopt(connection: $0) }
        listener.stateUpdateHandler = { [weak self] in self?.handleListenerState($0) }
        return try await withCheckedThrowingContinuation { continuation in
            lock.withLock { startContinuation = continuation }
            listener.start(queue: queue)
        }
    }

    /// Fire-and-forget teardown (tests: `defer { server.stop() }`).
    func stop() {
        lock.withLock { listener }?.cancel()
        lock.withLock { connection }?.forceCancel()
        finishStreams()
    }

    /// Teardown that waits for the listener to actually release the port
    /// (needed by the connect-to-dead-port test to avoid a race).
    func stopAndWait() async {
        guard let listener = lock.withLock({ listener }) else { return }
        await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
            lock.withLock { stopContinuation = continuation }
            listener.cancel()
        }
        lock.withLock { connection }?.forceCancel()
        finishStreams()
    }

    // MARK: - Scripted server actions

    /// Send one text frame to the client.
    func send(text: String) {
        sendToCurrentConnection(opcode: Wire.opcodeText, payload: [UInt8](text.utf8))
    }

    /// Send one binary frame (the real server never does — untrusted-input test).
    func send(binary payload: [UInt8]) {
        sendToCurrentConnection(opcode: Wire.opcodeBinary, payload: payload)
    }

    /// Send a WS close frame with the given status code (clean close path).
    func sendClose(code: UInt16) {
        let payload = [UInt8(code >> 8), UInt8(code & 0xFF)]
        sendToCurrentConnection(opcode: Wire.opcodeClose, payload: payload)
    }

    /// Abrupt TCP termination WITHOUT a WS close frame (transport-error path).
    func abort() {
        lock.withLock { connection }?.forceCancel()
    }

    // MARK: - Connection handling

    private func adopt(connection newConnection: NWConnection) {
        lock.withLock {
            connection = newConnection
            rxBuffer = []
            isHandshakeDone = false
        }
        newConnection.start(queue: queue)
        receiveNext(on: newConnection)
    }

    private func receiveNext(on connection: NWConnection) {
        connection.receive(
            minimumIncompleteLength: 1, maximumLength: Wire.receiveChunkLimit
        ) { [weak self] data, _, isComplete, error in
            guard let self else { return }
            if let data, !data.isEmpty {
                self.ingest(bytes: [UInt8](data))
            }
            guard error == nil, !isComplete else { return }
            guard let current = self.lock.withLock({ self.connection }) else { return }
            self.receiveNext(on: current)
        }
    }

    private func ingest(bytes: [UInt8]) {
        let current: NWConnection? = lock.withLock {
            rxBuffer += bytes
            return connection
        }
        guard let current else { return }
        tryCompleteHandshake(on: current)
        drainClientFrames(on: current)
    }

    private func handleListenerState(_ state: NWListener.State) {
        switch state {
        case .ready:
            let port = lock.withLock { listener?.port?.rawValue }
            takeStartContinuation()?.resume(returning: port ?? 0)
        case .failed(let error):
            takeStartContinuation()?.resume(throwing: error)
        case .cancelled:
            takeStopContinuation()?.resume()
        default:
            break
        }
    }

    // MARK: - Handshake

    private func tryCompleteHandshake(on connection: NWConnection) {
        let requestBytes: [UInt8]? = lock.withLock {
            guard !isHandshakeDone, let end = Self.headerEndIndex(in: rxBuffer) else {
                return nil
            }
            let request = Array(rxBuffer[..<end])
            rxBuffer.removeFirst(end + Wire.headerTerminator.count)
            isHandshakeDone = true
            return request
        }
        guard let requestBytes else { return }
        let upgrade = Self.parseUpgrade(String(decoding: requestBytes, as: UTF8.self))
        connection.send(
            content: Self.handshakeResponse(for: upgrade),
            completion: .contentProcessed { _ in }
        )
        upgradesContinuation.yield(upgrade)
    }

    private static func headerEndIndex(in bytes: [UInt8]) -> Int? {
        let terminator = Wire.headerTerminator
        guard bytes.count >= terminator.count else { return nil }
        for start in 0...(bytes.count - terminator.count)
        where Array(bytes[start..<(start + terminator.count)]) == terminator {
            return start
        }
        return nil
    }

    private static func parseUpgrade(_ text: String) -> Upgrade {
        let lines = text.components(separatedBy: "\r\n")
        var headers: [String: String] = [:]
        for line in lines.dropFirst() {
            guard let colon = line.firstIndex(of: ":") else { continue }
            let name = line[..<colon].trimmingCharacters(in: .whitespaces).lowercased()
            let value = line[line.index(after: colon)...].trimmingCharacters(in: .whitespaces)
            headers[name] = value
        }
        return Upgrade(requestLine: lines.first ?? "", headers: headers)
    }

    private static func handshakeResponse(for upgrade: Upgrade) -> Data {
        let key = upgrade.headers["sec-websocket-key"] ?? ""
        let digest = Insecure.SHA1.hash(data: Data((key + Wire.acceptGUID).utf8))
        let accept = Data(digest).base64EncodedString()
        let response = "HTTP/1.1 101 Switching Protocols\r\n"
            + "Upgrade: websocket\r\n"
            + "Connection: Upgrade\r\n"
            + "Sec-WebSocket-Accept: \(accept)\r\n\r\n"
        return Data(response.utf8)
    }

    // MARK: - Client frame parsing

    private func drainClientFrames(on connection: NWConnection) {
        while true {
            let frame: (opcode: UInt8, payload: [UInt8])? = lock.withLock {
                guard isHandshakeDone, let parsed = Self.parseFrame(rxBuffer) else {
                    return nil
                }
                rxBuffer.removeFirst(parsed.consumed)
                return (parsed.opcode, parsed.payload)
            }
            guard let frame else { return }
            dispatch(frame: frame, on: connection)
        }
    }

    private func dispatch(frame: (opcode: UInt8, payload: [UInt8]), on connection: NWConnection) {
        switch frame.opcode {
        case Wire.opcodeText:
            clientTextContinuation.yield(String(decoding: frame.payload, as: UTF8.self))
        case Wire.opcodePing:
            // Echo the payload back as a pong (RFC 6455 §5.5.3).
            rawSend(opcode: Wire.opcodePong, payload: frame.payload, on: connection)
        case Wire.opcodeClose:
            rawSend(opcode: Wire.opcodeClose, payload: frame.payload, on: connection)
            connection.cancel()
        default:
            break // binary/pong/continuation from the client — irrelevant here
        }
    }

    /// Parse one complete (possibly masked) client frame; nil while incomplete.
    private static func parseFrame(
        _ bytes: [UInt8]
    ) -> (opcode: UInt8, payload: [UInt8], consumed: Int)? {
        guard bytes.count >= 2 else { return nil }
        let opcode = bytes[0] & Wire.opcodeMask
        let isMasked = bytes[1] & Wire.maskBit != 0
        var length = Int(bytes[1] & Wire.payloadLenMask)
        var offset = 2
        if length == Wire.len16Marker {
            guard bytes.count >= offset + 2 else { return nil }
            length = Int(bytes[offset]) << 8 | Int(bytes[offset + 1])
            offset += 2
        } else if length == Wire.len64Marker {
            guard bytes.count >= offset + 8 else { return nil }
            length = bytes[offset..<(offset + 8)].reduce(0) { ($0 << 8) | Int($1) }
            offset += 8
        }
        let maskCount = isMasked ? Wire.maskKeyLength : 0
        guard bytes.count >= offset + maskCount + length else { return nil }
        var payload = Array(bytes[(offset + maskCount)..<(offset + maskCount + length)])
        if isMasked {
            let mask = Array(bytes[offset..<(offset + maskCount)])
            for index in payload.indices {
                payload[index] ^= mask[index % Wire.maskKeyLength]
            }
        }
        return (opcode, payload, offset + maskCount + length)
    }

    // MARK: - Server frame encoding (server→client frames are unmasked)

    private func sendToCurrentConnection(opcode: UInt8, payload: [UInt8]) {
        guard let connection = lock.withLock({ connection }) else { return }
        rawSend(opcode: opcode, payload: payload, on: connection)
    }

    private func rawSend(opcode: UInt8, payload: [UInt8], on connection: NWConnection) {
        connection.send(
            content: Self.encodeServerFrame(opcode: opcode, payload: payload),
            completion: .contentProcessed { _ in }
        )
    }

    private static func encodeServerFrame(opcode: UInt8, payload: [UInt8]) -> Data {
        var frame: [UInt8] = [Wire.finBit | opcode]
        let count = payload.count
        if count <= Wire.maxTinyPayload {
            frame.append(UInt8(count))
        } else if count <= Int(UInt16.max) {
            frame.append(UInt8(Wire.len16Marker))
            frame.append(UInt8((count >> 8) & 0xFF))
            frame.append(UInt8(count & 0xFF))
        } else {
            frame.append(UInt8(Wire.len64Marker))
            for shift in stride(from: 56, through: 0, by: -8) {
                frame.append(UInt8((count >> shift) & 0xFF))
            }
        }
        frame += payload
        return Data(frame)
    }

    // MARK: - Continuation bookkeeping

    private func takeStartContinuation() -> CheckedContinuation<UInt16, any Error>? {
        lock.withLock {
            defer { startContinuation = nil }
            return startContinuation
        }
    }

    private func takeStopContinuation() -> CheckedContinuation<Void, Never>? {
        lock.withLock {
            defer { stopContinuation = nil }
            return stopContinuation
        }
    }

    private func finishStreams() {
        upgradesContinuation.finish()
        clientTextContinuation.finish()
    }
}
#endif
