/**
 * Real agent-facing mTLS server for `main.ts`. A `TlsServerFactory` that stands up an https server
 * (`requestCert: true`, `rejectUnauthorized: true`, pinned dev CA) with a `ws` WebSocketServer over
 * it, so an agent dials `wss://` under mTLS. The TLS layer rejects a no-cert / non-chaining peer
 * BEFORE `attach()` runs (Finding-4 two-tier defense); `verifyPeer` (P5) then binds the cert to the
 * registry. Every connection's DER cert is handed to the relay's `onPeer`.
 */
import { readFileSync } from 'node:fs'
import { createServer } from 'node:https'
import type { TLSSocket } from 'node:tls'
import type { IncomingMessage } from 'node:http'
import { WebSocketServer, type WebSocket as WsWebSocket } from 'ws'
import type { TlsServerFactory, TlsServerLike } from 'term-relay/data-plane/agent-listener.js'
import { wsToWebSocketLike } from '../wiring/socket-pipe.js'

export interface AgentTlsOptions {
  readonly serverCertPath: string
  readonly serverKeyPath: string
  readonly bindHost: string
  readonly bindPort: number
  readonly onListening?: () => void
  readonly onError?: (e: unknown) => void
}

export function makeAgentTlsServerFactory(opts: AgentTlsOptions): TlsServerFactory {
  return (tlsOpts, onPeer): TlsServerLike => {
    const server = createServer({
      cert: readFileSync(opts.serverCertPath),
      key: readFileSync(opts.serverKeyPath),
      ca: tlsOpts.ca.map((b) => Buffer.from(b)),
      requestCert: tlsOpts.requestCert,
      rejectUnauthorized: tlsOpts.rejectUnauthorized,
    })
    const wss = new WebSocketServer({ server })
    wss.on('connection', (ws: WsWebSocket, req: IncomingMessage) => {
      const peer = (req.socket as TLSSocket).getPeerCertificate(true)
      const der = peer && peer.raw ? new Uint8Array(peer.raw) : new Uint8Array()
      onPeer(wsToWebSocketLike(ws), der)
    })
    wss.on('error', (e) => opts.onError?.(e))
    // Surface TLS-layer client failures (e.g. a client leaf that doesn't chain to `ca`). Node
    // otherwise SWALLOWS 'tlsClientError' — the peer just sees an abrupt reset with no server signal,
    // which is exactly what masked the intermediate-only-CA bug.
    server.on('tlsClientError', (e) => opts.onError?.(e))
    server.on('error', (e) => opts.onError?.(e))
    server.listen(opts.bindPort, opts.bindHost, () => opts.onListening?.())
    return {
      close: () => {
        wss.close()
        server.close()
      },
    }
  }
}
