import { getDebugNetworkMetricSnapshot } from '../../../infrastructure/realtime/logging/debug-network-metrics';
import type { Room, User } from '../../models/index';
import {
  LOCAL_NETWORK_NODE_ID,
  NETWORK_DOWNLOAD_STAT_TTL_MS,
  NETWORK_FILE_TRANSFER_RATE_WINDOW_MS,
  NETWORK_IGNORED_MESSAGE_TYPES,
  NETWORK_MESSAGE_GROUP_LIMIT,
  NETWORK_RECENT_EDGE_TTL_MS,
  NETWORK_TYPING_TTL_MS,
  createEmptyDownloadStats,
  createEmptyHandshakeStats,
  createEmptyStreamStats,
  createEmptyTextStats
} from './debugging.constants';
import type {
  DebugLogEntry,
  DebugNetworkBuildState,
  DebugNetworkDownloadStats,
  DebugNetworkEdge,
  DebugNetworkEdgeKind,
  DebugNetworkMessageDirection,
  DebugNetworkMessageScope,
  DebugNetworkNode,
  DebugNetworkNodeKind,
  DebugNetworkSnapshot,
  DebugNetworkTransferSample,
  MutableDebugNetworkEdge,
  MutableDebugNetworkNode
} from '../../models/debugging.models';

interface FinalizedNodePresentation {
  userId: string | null;
  label: string;
  secondaryLabel: string;
  title: string;
  isActive: boolean;
}

export function buildDebugNetworkSnapshot(
  entries: readonly DebugLogEntry[],
  currentUser: User | null,
  allUsers: readonly User[],
  currentRoom: Room | null
): DebugNetworkSnapshot {
  return new DebugNetworkSnapshotBuilder(currentUser, allUsers, currentRoom).build(entries);
}

class DebugNetworkSnapshotBuilder {
  constructor(
    private readonly currentUser: User | null,
    private readonly allUsers: readonly User[],
    private readonly currentRoom: Room | null
  ) {}

  build(entries: readonly DebugLogEntry[]): DebugNetworkSnapshot {
    const now = Date.now();
    const state = this.createNetworkBuildState(now);

    for (const entry of entries) {
      this.applyEntryToNetworkState(state, entry);
    }

    this.applyLiveUserNetworkState(state, now);

    const visibleEdges = Array.from(state.edges.values())
      .filter((edge) => this.shouldIncludeNetworkEdge(edge, now))
      .sort((edgeA, edgeB) => this.compareNetworkEdges(edgeA, edgeB));
    const visibleNodeIds = new Set<string>([LOCAL_NETWORK_NODE_ID]);
    const activeNodeIds = new Set<string>([LOCAL_NETWORK_NODE_ID]);

    for (const edge of visibleEdges) {
      visibleNodeIds.add(edge.sourceId);
      visibleNodeIds.add(edge.targetId);

      if (edge.isActive) {
        activeNodeIds.add(edge.sourceId);
        activeNodeIds.add(edge.targetId);
      }
    }

    const visibleNodes = Array.from(state.nodes.values())
      .filter((node) => visibleNodeIds.has(node.id) || node.kind === 'local-client')
      .map((node) => this.finalizeNetworkNode(node, state, now, activeNodeIds.has(node.id)))
      .sort((nodeA, nodeB) => this.compareFinalNetworkNodes(nodeA, nodeB));
    const nodeLookup = new Map(visibleNodes.map((node) => [node.id, node]));
    const finalizedEdges = visibleEdges
      .map((edge) => this.finalizeNetworkEdge(edge, nodeLookup))
      .filter((edge): edge is DebugNetworkEdge => edge !== null);
    const summary = {
      clientCount: visibleNodes.filter((node) => node.kind === 'local-client' || node.kind === 'remote-client').length,
      serverCount: visibleNodes.filter((node) => node.kind === 'app-server').length,
      signalingServerCount: visibleNodes.filter((node) => node.kind === 'signaling-server').length,
      peerConnectionCount: finalizedEdges.filter((edge) => edge.kind === 'peer' && edge.isActive).length,
      membershipCount: finalizedEdges.filter((edge) => edge.kind === 'membership' && edge.isActive).length,
      messageCount: finalizedEdges.reduce((sum, edge) => sum + edge.messageTotal, 0),
      typingCount: visibleNodes.filter((node) => node.isTyping).length,
      speakingCount: visibleNodes.filter((node) => node.isSpeaking).length,
      streamingCount: visibleNodes.filter((node) => node.isStreaming).length
    };

    return {
      nodes: visibleNodes,
      edges: finalizedEdges,
      summary,
      generatedAt: now
    };
  }

  private createNetworkBuildState(now: number): DebugNetworkBuildState {
    const localIds = new Set<string>();

    if (this.currentUser?.id)
      localIds.add(this.currentUser.id);

    if (this.currentUser?.oderId)
      localIds.add(this.currentUser.oderId);

    const state: DebugNetworkBuildState = {
      currentRoom: this.currentRoom,
      currentUser: this.currentUser,
      edges: new Map<string, MutableDebugNetworkEdge>(),
      localIds,
      nodes: new Map<string, MutableDebugNetworkNode>(),
      users: this.allUsers,
      userLookup: this.buildNetworkUserLookup(this.allUsers)
    };

    this.ensureLocalNetworkNode(state, now);

    return state;
  }

  private buildNetworkUserLookup(allUsers: readonly User[]): Map<string, User> {
    const lookup = new Map<string, User>();

    for (const user of allUsers) {
      lookup.set(user.id, user);

      if (user.oderId)
        lookup.set(user.oderId, user);
    }

    return lookup;
  }

  private applyEntryToNetworkState(state: DebugNetworkBuildState, entry: DebugLogEntry): void {
    switch (entry.source) {
      case 'webrtc:signaling':
        this.applySignalingNetworkEntry(state, entry);
        return;
      case 'webrtc:data-channel':
        this.applyDataChannelNetworkEntry(state, entry);
        return;
      case 'webrtc:voice-activity':
        this.applyVoiceActivityNetworkEntry(state, entry);
        return;
      case 'webrtc':
        this.applyGenericWebRTCNetworkEntry(state, entry);
        return;
    }
  }

  private applySignalingNetworkEntry(state: DebugNetworkBuildState, entry: DebugLogEntry): void {
    const payload = this.getEntryPayloadRecord(entry.payload);
    const timestamp = entry.timestamp;

    if (this.applySignalingServerStateChange(state, entry.message, payload, timestamp))
      return;

    if (entry.message !== 'inbound' && entry.message !== 'outbound')
      return;

    const direction = entry.message as DebugNetworkMessageDirection;
    const type = this.getPayloadString(payload, 'type') ?? 'unknown';

    this.recordSignalingTransportMessage(state, payload, type, direction, timestamp, entry.count);

    switch (type) {
      case 'identify':
        this.applySignalingIdentifyMessage(state, direction, payload, timestamp);
        return;
      case 'connected':
        this.applySignalingConnectedMessage(state, payload, timestamp);
        return;
      case 'join_server':
      case 'view_server':
      case 'leave_server':
        this.applySignalingMembershipMessage(state, type, payload, timestamp);
        return;
      case 'server_users':
        this.applySignalingServerUsersMessage(state, payload, timestamp);
        return;
      case 'user_joined':
      case 'user_left':
      case 'user_typing':
        this.applySignalingUserActivityMessage(state, type, payload, timestamp);
        return;
      case 'typing':
        this.ensureLocalNetworkNode(state, timestamp).typingExpiresAt = timestamp + NETWORK_TYPING_TTL_MS;
        return;
      case 'offer':
      case 'answer':
      case 'ice_candidate':
        this.applySignalingPeerHandshakeMessage(state, type, direction, payload, timestamp, entry.count);
        return;
    }
  }

  private applySignalingServerStateChange(
    state: DebugNetworkBuildState,
    message: string,
    payload: Record<string, unknown> | null,
    timestamp: number
  ): boolean {
    if (
      message !== 'Connecting to signaling server'
      && message !== 'Connected to signaling server'
      && message !== 'Attempting reconnect'
      && message !== 'Disconnected from signaling server'
      && message !== 'Signaling socket error'
      && message !== 'Failed to initialize signaling socket'
    ) {
      return false;
    }

    const url = this.getPayloadString(payload, 'serverUrl') ?? this.getPayloadString(payload, 'url');

    if (!url)
      return true;

    const serverNode = this.ensureSignalingServerNode(state, url, timestamp);
    const edge = this.ensureNetworkEdge(state, 'signaling', LOCAL_NETWORK_NODE_ID, serverNode.id, timestamp);

    edge.stateLabel = this.getSignalingEdgeStateLabel(message);
    edge.isActive = edge.stateLabel === 'connected' || edge.stateLabel === 'connecting' || edge.stateLabel === 'active';

    return true;
  }

  private recordSignalingTransportMessage(
    state: DebugNetworkBuildState,
    payload: Record<string, unknown> | null,
    type: string,
    direction: DebugNetworkMessageDirection,
    timestamp: number,
    count: number
  ): void {
    const url = this.getPayloadString(payload, 'url');

    if (!url)
      return;

    const signalingNode = this.ensureSignalingServerNode(state, url, timestamp);
    const signalingEdge = this.ensureNetworkEdge(state, 'signaling', LOCAL_NETWORK_NODE_ID, signalingNode.id, timestamp);

    signalingEdge.isActive = true;

    if (!signalingEdge.stateLabel || signalingEdge.stateLabel === 'disconnected')
      signalingEdge.stateLabel = 'active';

    this.recordNetworkMessage(signalingEdge, type, direction, 'signaling', timestamp, count);
  }

  private applySignalingIdentifyMessage(
    state: DebugNetworkBuildState,
    direction: DebugNetworkMessageDirection,
    payload: Record<string, unknown> | null,
    timestamp: number
  ): void {
    if (direction !== 'outbound')
      return;

    const oderId = this.getPayloadString(payload, 'oderId');
    const displayName = this.getPayloadString(payload, 'displayName');

    this.ensureLocalNetworkNode(state, timestamp, oderId, displayName);
  }

  private applySignalingConnectedMessage(
    state: DebugNetworkBuildState,
    payload: Record<string, unknown> | null,
    timestamp: number
  ): void {
    const oderId = this.getPayloadString(payload, 'oderId');

    if (oderId)
      this.ensureLocalNetworkNode(state, timestamp, oderId);
  }

  private applySignalingMembershipMessage(
    state: DebugNetworkBuildState,
    type: 'join_server' | 'view_server' | 'leave_server',
    payload: Record<string, unknown> | null,
    timestamp: number
  ): void {
    const serverId = this.getPayloadString(payload, 'serverId');

    if (!serverId)
      return;

    const serverNode = this.ensureAppServerNode(state, serverId, timestamp);
    const membershipEdge = this.ensureNetworkEdge(state, 'membership', LOCAL_NETWORK_NODE_ID, serverNode.id, timestamp);

    membershipEdge.isActive = type !== 'leave_server';
    membershipEdge.stateLabel = type === 'view_server'
      ? 'viewing'
      : (type === 'join_server' ? 'joined' : 'left');
  }

  private applySignalingServerUsersMessage(
    state: DebugNetworkBuildState,
    payload: Record<string, unknown> | null,
    timestamp: number
  ): void {
    const serverId = this.getPayloadString(payload, 'serverId');
    const users = this.getPayloadArray(payload, 'users');

    if (!serverId)
      return;

    const serverNode = this.ensureAppServerNode(state, serverId, timestamp);

    for (const userValue of users) {
      const userRecord = this.asRecord(userValue);
      const userId = this.getStringProperty(userRecord, 'oderId');

      if (!userId)
        continue;

      const clientNode = this.ensureClientNetworkNode(
        state,
        userId,
        timestamp,
        this.getStringProperty(userRecord, 'displayName')
      );
      const membershipEdge = this.ensureNetworkEdge(state, 'membership', clientNode.id, serverNode.id, timestamp);

      membershipEdge.isActive = true;
      membershipEdge.stateLabel = 'joined';
    }
  }

  private applySignalingUserActivityMessage(
    state: DebugNetworkBuildState,
    type: 'user_joined' | 'user_left' | 'user_typing',
    payload: Record<string, unknown> | null,
    timestamp: number
  ): void {
    const oderId = this.getPayloadString(payload, 'oderId');
    const displayName = this.getPayloadString(payload, 'displayName');
    const serverId = this.getPayloadString(payload, 'serverId');

    if (!oderId)
      return;

    const clientNode = this.ensureClientNetworkNode(state, oderId, timestamp, displayName);

    if (type === 'user_typing')
      clientNode.typingExpiresAt = timestamp + NETWORK_TYPING_TTL_MS;

    if (!serverId)
      return;

    const serverNode = this.ensureAppServerNode(state, serverId, timestamp);
    const membershipEdge = this.ensureNetworkEdge(state, 'membership', clientNode.id, serverNode.id, timestamp);

    membershipEdge.isActive = type !== 'user_left';
    membershipEdge.stateLabel = type === 'user_joined' ? 'joined' : (type === 'user_left' ? 'left' : 'active');
  }

  private applySignalingPeerHandshakeMessage(
    state: DebugNetworkBuildState,
    type: 'offer' | 'answer' | 'ice_candidate',
    direction: DebugNetworkMessageDirection,
    payload: Record<string, unknown> | null,
    timestamp: number,
    count: number
  ): void {
    const peerId = direction === 'outbound'
      ? (this.getPayloadString(payload, 'targetPeerId') ?? this.getPayloadString(payload, 'fromUserId'))
      : (this.getPayloadString(payload, 'fromUserId') ?? this.getPayloadString(payload, 'targetPeerId'));
    const displayName = this.getPayloadString(payload, 'displayName');

    if (!peerId)
      return;

    const peerNode = this.ensureClientNetworkNode(state, peerId, timestamp, displayName);
    const peerEdge = this.ensureNetworkEdge(state, 'peer', LOCAL_NETWORK_NODE_ID, peerNode.id, timestamp);

    this.incrementHandshakeStats(peerNode, type, direction, count);
    this.recordNetworkMessage(peerEdge, type, direction, 'signaling', timestamp, count);
    peerEdge.isActive = true;

    if (peerEdge.stateLabel !== 'connected')
      peerEdge.stateLabel = 'negotiating';
  }

  private applyDataChannelNetworkEntry(state: DebugNetworkBuildState, entry: DebugLogEntry): void {
    const payload = this.getEntryPayloadRecord(entry.payload);
    const timestamp = entry.timestamp;

    if (this.applyDataChannelLatencyMessage(state, entry.message, payload, timestamp))
      return;

    if (this.applyDataChannelStateMessage(state, entry.message, payload, timestamp))
      return;

    if (entry.message !== 'inbound' && entry.message !== 'outbound')
      return;

    this.applyDataChannelPayloadMessage(
      state,
      payload,
      entry.message as DebugNetworkMessageDirection,
      timestamp,
      entry.count
    );
  }

  private applyDataChannelLatencyMessage(
    state: DebugNetworkBuildState,
    message: string,
    payload: Record<string, unknown> | null,
    timestamp: number
  ): boolean {
    if (message !== 'Peer latency updated')
      return false;

    const peerId = this.getPayloadString(payload, 'peerId');
    const latencyMs = this.getPayloadNumber(payload, 'latencyMs');

    if (!peerId || latencyMs === null)
      return true;

    const peerNode = this.ensureClientNetworkNode(state, peerId, timestamp);
    const edge = this.ensureNetworkEdge(state, 'peer', LOCAL_NETWORK_NODE_ID, peerNode.id, timestamp);

    edge.isActive = true;
    edge.pingMs = latencyMs;
    edge.stateLabel = 'connected';
    peerNode.pingMs = latencyMs;

    return true;
  }

  private applyDataChannelStateMessage(
    state: DebugNetworkBuildState,
    message: string,
    payload: Record<string, unknown> | null,
    timestamp: number
  ): boolean {
    if (message !== 'Data channel open' && message !== 'Data channel closed' && message !== 'Data channel error')
      return false;

    const peerId = this.getPayloadString(payload, 'peerId');

    if (!peerId)
      return true;

    const peerNode = this.ensureClientNetworkNode(state, peerId, timestamp);
    const edge = this.ensureNetworkEdge(state, 'peer', LOCAL_NETWORK_NODE_ID, peerNode.id, timestamp);

    if (message === 'Data channel open') {
      edge.isActive = true;
      edge.stateLabel = 'connected';
      return true;
    }

    edge.isActive = false;
    edge.stateLabel = message === 'Data channel closed' ? 'closed' : 'error';

    if (message === 'Data channel closed')
      peerNode.isSpeaking = false;

    return true;
  }

  private applyDataChannelPayloadMessage(
    state: DebugNetworkBuildState,
    payload: Record<string, unknown> | null,
    direction: DebugNetworkMessageDirection,
    timestamp: number,
    count: number
  ): void {
    const peerId = this.getPayloadString(payload, 'peerId');

    if (!peerId)
      return;

    const peerNode = this.ensureClientNetworkNode(state, peerId, timestamp, this.getPayloadString(payload, 'displayName'));
    const edge = this.ensureNetworkEdge(state, 'peer', LOCAL_NETWORK_NODE_ID, peerNode.id, timestamp);
    const type = this.getPayloadString(payload, 'type') ?? 'unknown';

    edge.isActive = true;
    edge.stateLabel = 'connected';
    this.recordNetworkMessage(edge, type, direction, 'data-channel', timestamp, count);

    if (type === 'chat-message' || type === 'message')
      this.incrementTextMessageCount(peerNode, direction, count);

    if (type === 'file-chunk' && direction === 'inbound') {
      const bytes = this.getPayloadNumber(payload, 'bytes');

      if (bytes !== null)
        this.recordFileTransferSample(peerNode, timestamp, bytes, count);
    }

    if (direction === 'outbound') {
      const outboundIdentity = this.getPayloadString(payload, 'oderId');

      if (outboundIdentity) {
        this.ensureLocalNetworkNode(
          state,
          timestamp,
          outboundIdentity,
          this.getPayloadString(payload, 'displayName')
        );
      }
    }

    if (type === 'voice-state') {
      this.applyVoiceStateDataChannelMessage(state, payload, direction, peerNode, timestamp);
      return;
    }

    if (type === 'screen-state' || type === 'camera-state')
      this.applyStreamingStateDataChannelMessage(state, type, payload, direction, peerNode, timestamp);
  }

  private applyVoiceStateDataChannelMessage(
    state: DebugNetworkBuildState,
    payload: Record<string, unknown> | null,
    direction: DebugNetworkMessageDirection,
    peerNode: MutableDebugNetworkNode,
    timestamp: number
  ): void {
    const voiceState = this.getPayloadRecord(payload, 'voiceState');
    const subjectNode = direction === 'outbound'
      ? this.ensureLocalNetworkNode(
        state,
        timestamp,
        this.getPayloadString(payload, 'oderId'),
        this.getPayloadString(payload, 'displayName')
      )
      : peerNode;

    this.applyVoiceStateToNetworkNode(subjectNode, voiceState);

    const serverId = this.getStringProperty(voiceState, 'serverId') ?? this.getStringProperty(voiceState, 'roomId');

    if (!serverId)
      return;

    const serverNode = this.ensureAppServerNode(state, serverId, timestamp);
    const membershipEdge = this.ensureNetworkEdge(state, 'membership', subjectNode.id, serverNode.id, timestamp);

    membershipEdge.isActive = true;
    membershipEdge.stateLabel = 'joined';
  }

  private applyStreamingStateDataChannelMessage(
    state: DebugNetworkBuildState,
    type: 'screen-state' | 'camera-state',
    payload: Record<string, unknown> | null,
    direction: DebugNetworkMessageDirection,
    peerNode: MutableDebugNetworkNode,
    timestamp: number
  ): void {
    const subjectNode = direction === 'outbound'
      ? this.ensureLocalNetworkNode(
        state,
        timestamp,
        this.getPayloadString(payload, 'oderId'),
        this.getPayloadString(payload, 'displayName')
      )
      : peerNode;
    const isStreaming = type === 'screen-state'
      ? this.getPayloadBoolean(payload, 'isScreenSharing')
      : this.getPayloadBoolean(payload, 'isCameraEnabled');

    if (isStreaming === null)
      return;

    subjectNode.isStreaming = isStreaming;

    if (!isStreaming)
      subjectNode.streams.video = 0;
  }

  private applyGenericWebRTCNetworkEntry(state: DebugNetworkBuildState, entry: DebugLogEntry): void {
    const payload = this.getEntryPayloadRecord(entry.payload);
    const timestamp = entry.timestamp;
    const peerId = this.getStringProperty(payload, 'remotePeerId') ?? this.getStringProperty(payload, 'peerId');

    if (!peerId)
      return;

    const peerNode = this.ensureClientNetworkNode(state, peerId, timestamp);
    const edge = this.ensureNetworkEdge(state, 'peer', LOCAL_NETWORK_NODE_ID, peerNode.id, timestamp);

    switch (entry.message) {
      case 'Creating peer connection':
      case 'Received data channel':
        this.markPeerEdgeConnecting(edge);
        return;

      case 'connectionstatechange':
        this.applyGenericConnectionStateMessage(peerNode, edge, payload);
        return;

      case 'Remote stream updated':
        this.applyGenericRemoteStreamMessage(peerNode, edge, payload);
        return;

      case 'Peer transport stats':
        this.applyGenericTransportStatsMessage(peerNode, edge, payload, timestamp);
        return;
    }
  }

  private markPeerEdgeConnecting(edge: MutableDebugNetworkEdge): void {
    edge.isActive = true;

    if (edge.stateLabel !== 'connected')
      edge.stateLabel = 'connecting';
  }

  private applyGenericConnectionStateMessage(
    peerNode: MutableDebugNetworkNode,
    edge: MutableDebugNetworkEdge,
    payload: Record<string, unknown> | null
  ): void {
    const connectionState = this.getStringProperty(payload, 'state');

    if (!connectionState)
      return;

    const previousState = edge.stateLabel;

    edge.stateLabel = connectionState;
    edge.isActive = connectionState === 'connected' || connectionState === 'connecting';

    if (edge.isActive)
      return;

    peerNode.isSpeaking = false;

    if (connectionState !== 'disconnected' && connectionState !== 'failed')
      return;

    if (previousState !== connectionState)
      peerNode.connectionDrops += 1;

    peerNode.streams.audio = 0;
    peerNode.streams.video = 0;
  }

  private applyGenericRemoteStreamMessage(
    peerNode: MutableDebugNetworkNode,
    edge: MutableDebugNetworkEdge,
    payload: Record<string, unknown> | null
  ): void {
    const audioTrackCount = this.getNumberProperty(payload, 'audioTrackCount');
    const videoTrackCount = this.getNumberProperty(payload, 'videoTrackCount');

    edge.isActive = true;

    if (!edge.stateLabel || edge.stateLabel === 'negotiating')
      edge.stateLabel = 'connected';

    if (audioTrackCount !== null)
      peerNode.streams.audio = Math.max(0, Math.round(audioTrackCount));

    if (videoTrackCount !== null)
      peerNode.streams.video = Math.max(0, Math.round(videoTrackCount));
  }

  private applyGenericTransportStatsMessage(
    peerNode: MutableDebugNetworkNode,
    edge: MutableDebugNetworkEdge,
    payload: Record<string, unknown> | null,
    timestamp: number
  ): void {
    edge.isActive = true;

    if (!edge.stateLabel || edge.stateLabel === 'negotiating')
      edge.stateLabel = 'connected';

    this.updateNodeDownloadStats(peerNode, {
      audioMbps: this.getNumberProperty(payload, 'audioDownloadMbps'),
      videoMbps: this.getNumberProperty(payload, 'videoDownloadMbps')
    }, timestamp);
  }

  private applyVoiceActivityNetworkEntry(state: DebugNetworkBuildState, entry: DebugLogEntry): void {
    const payload = this.getEntryPayloadRecord(entry.payload);
    const peerId = this.getStringProperty(payload, 'peerId');
    const isSpeaking = this.getBooleanProperty(payload, 'isSpeaking');

    if (!peerId || isSpeaking === null)
      return;

    const node = this.ensureClientNetworkNode(state, peerId, entry.timestamp);

    node.isSpeaking = isSpeaking;
    node.lastSeen = Math.max(node.lastSeen, entry.timestamp);
  }

  private applyLiveUserNetworkState(state: DebugNetworkBuildState, now: number): void {
    const localUser = state.currentUser;
    const localIdentity = localUser ? this.getUserNetworkIdentity(localUser) : null;
    const localVoiceServerId = localUser ? this.getUserVoiceServerId(localUser) : null;
    const localVoiceConnected = localUser?.voiceState?.isConnected === true;

    this.applyLiveLocalUserState(state, localUser, localIdentity, localVoiceServerId, localVoiceConnected, now);

    for (const user of state.users) {
      this.applyLiveRemoteUserState(state, user, localVoiceConnected, localVoiceServerId, now);
    }
  }

  private applyLiveLocalUserState(
    state: DebugNetworkBuildState,
    localUser: User | null,
    localIdentity: string | null,
    localVoiceServerId: string | null,
    localVoiceConnected: boolean,
    now: number
  ): void {
    if (!localUser || !localIdentity)
      return;

    const localNode = this.ensureLocalNetworkNode(state, now, localIdentity, localUser.displayName);

    this.applyUserStateToNetworkNode(localNode, localUser, now);

    if (!localVoiceServerId)
      return;

    const serverNode = this.ensureAppServerNode(state, localVoiceServerId, now);
    const membershipEdge = this.ensureNetworkEdge(state, 'membership', localNode.id, serverNode.id, now);

    membershipEdge.isActive = true;
    membershipEdge.stateLabel = localVoiceConnected ? 'joined' : 'viewing';
    membershipEdge.lastSeen = now;
  }

  private applyLiveRemoteUserState(
    state: DebugNetworkBuildState,
    user: User,
    localVoiceConnected: boolean,
    localVoiceServerId: string | null,
    now: number
  ): void {
    const identity = this.getUserNetworkIdentity(user);

    if (!identity)
      return;

    const node = this.isLocalIdentity(state, identity)
      ? this.ensureLocalNetworkNode(state, now, identity, user.displayName)
      : this.ensureClientNetworkNode(state, identity, now, user.displayName);

    this.applyUserStateToNetworkNode(node, user, now);

    const voiceServerId = this.getUserVoiceServerId(user);

    this.syncLiveUserMembershipEdge(state, node, voiceServerId, user.voiceState?.isConnected === true, now);

    if (
      this.isLocalIdentity(state, identity)
      || !localVoiceConnected
      || user.voiceState?.isConnected !== true
      || !voiceServerId
      || !localVoiceServerId
      || voiceServerId !== localVoiceServerId
    ) {
      return;
    }

    const peerEdge = this.ensureNetworkEdge(state, 'peer', LOCAL_NETWORK_NODE_ID, node.id, now);

    peerEdge.isActive = true;
    peerEdge.stateLabel = 'connected';
    peerEdge.lastSeen = now;

    if (node.pingMs !== null)
      peerEdge.pingMs = node.pingMs;
  }

  private syncLiveUserMembershipEdge(
    state: DebugNetworkBuildState,
    node: MutableDebugNetworkNode,
    voiceServerId: string | null,
    isVoiceConnected: boolean,
    now: number
  ): void {
    if (!voiceServerId)
      return;

    const serverNode = this.ensureAppServerNode(state, voiceServerId, now);
    const membershipEdge = this.ensureNetworkEdge(state, 'membership', node.id, serverNode.id, now);

    membershipEdge.isActive = isVoiceConnected;
    membershipEdge.stateLabel = isVoiceConnected ? 'joined' : 'inactive';

    if (isVoiceConnected)
      membershipEdge.lastSeen = now;
  }

  private applyUserStateToNetworkNode(node: MutableDebugNetworkNode, user: User, now: number): void {
    node.label = user.displayName || user.username || node.label;
    node.secondaryLabel = user.username ? `@${user.username}` : node.secondaryLabel;
    node.title = user.displayName || user.username || node.title;
    node.userId = user.id || node.userId;
    node.isVoiceConnected = user.voiceState?.isConnected === true;
    node.isMuted = user.voiceState?.isMuted === true;
    node.isDeafened = user.voiceState?.isDeafened === true;
    node.isSpeaking = user.voiceState?.isSpeaking === true || node.isSpeaking;
    node.isStreaming = user.screenShareState?.isSharing === true;

    if (user.voiceState?.isConnected !== true)
      node.streams.audio = 0;

    if (user.screenShareState?.isSharing !== true)
      node.streams.video = 0;

    node.lastSeen = Math.max(node.lastSeen, now);
  }

  private getUserNetworkIdentity(user: User): string | null {
    return user.oderId || user.id || null;
  }

  private getUserVoiceServerId(user: User): string | null {
    return user.voiceState?.serverId || user.voiceState?.roomId || null;
  }

  private ensureLocalNetworkNode(
    state: DebugNetworkBuildState,
    timestamp: number,
    identity?: string | null,
    displayName?: string | null
  ): MutableDebugNetworkNode {
    const node = this.ensureNetworkNode(state, LOCAL_NETWORK_NODE_ID, 'local-client', identity ?? null, timestamp);
    const currentUser = state.currentUser;

    if (identity)
      state.localIds.add(identity);

    node.isActive = true;
    node.userId = currentUser?.id || node.userId;
    node.label = currentUser?.displayName || currentUser?.username || displayName || node.label || 'You';
    node.secondaryLabel = currentUser?.username ? `@${currentUser.username}` : 'You';
    node.title = currentUser?.displayName || displayName || 'You';

    return node;
  }

  private ensureClientNetworkNode(
    state: DebugNetworkBuildState,
    identity: string,
    timestamp: number,
    displayName?: string | null
  ): MutableDebugNetworkNode {
    if (this.isLocalIdentity(state, identity))
      return this.ensureLocalNetworkNode(state, timestamp, identity, displayName);

    const node = this.ensureNetworkNode(state, `client:${identity}`, 'remote-client', identity, timestamp);

    this.applyUserMetadataToNetworkNode(state, node, identity, displayName);

    return node;
  }

  private ensureSignalingServerNode(state: DebugNetworkBuildState, url: string, timestamp: number): MutableDebugNetworkNode {
    const node = this.ensureNetworkNode(state, `signal:${url}`, 'signaling-server', url, timestamp);

    node.label = this.getSignalingHostLabel(url);
    node.secondaryLabel = this.getSignalingSecondaryLabel(url);
    node.title = url;

    return node;
  }

  private ensureAppServerNode(state: DebugNetworkBuildState, serverId: string, timestamp: number): MutableDebugNetworkNode {
    const node = this.ensureNetworkNode(state, `server:${serverId}`, 'app-server', serverId, timestamp);
    const currentRoom = state.currentRoom;

    node.label = currentRoom?.id === serverId
      ? currentRoom.name
      : (node.label || `Server ${this.shortenIdentifier(serverId)}`);

    node.secondaryLabel = serverId;
    node.title = node.label;

    return node;
  }

  private ensureNetworkNode(
    state: DebugNetworkBuildState,
    nodeId: string,
    kind: DebugNetworkNodeKind,
    identity: string | null,
    timestamp: number
  ): MutableDebugNetworkNode {
    const existing = state.nodes.get(nodeId);

    if (existing) {
      existing.lastSeen = Math.max(existing.lastSeen, timestamp);

      if (identity && !existing.identity)
        existing.identity = identity;

      return existing;
    }

    const node: MutableDebugNetworkNode = {
      id: nodeId,
      identity,
      userId: null,
      kind,
      label: kind === 'local-client'
        ? 'You'
        : (kind === 'signaling-server' ? 'Signaling' : `Node ${identity ? this.shortenIdentifier(identity) : 'unknown'}`),
      secondaryLabel: identity || kind,
      title: identity || kind,
      lastSeen: timestamp,
      isActive: kind === 'local-client',
      isVoiceConnected: false,
      typingExpiresAt: null,
      isSpeaking: false,
      isMuted: false,
      isDeafened: false,
      isStreaming: false,
      connectionDrops: 0,
      downloads: createEmptyDownloadStats(),
      downloadsUpdatedAt: null,
      fileTransferSamples: [],
      handshake: createEmptyHandshakeStats(),
      pingMs: null,
      streams: createEmptyStreamStats(),
      textMessages: createEmptyTextStats()
    };

    state.nodes.set(nodeId, node);

    return node;
  }

  private applyUserMetadataToNetworkNode(
    state: DebugNetworkBuildState,
    node: MutableDebugNetworkNode,
    identity: string,
    displayName?: string | null
  ): void {
    const user = state.userLookup.get(identity);
    const label = user?.displayName || displayName || user?.username || node.label;

    node.identity = identity;
    node.userId = user?.id || node.userId;
    node.label = label;
    node.secondaryLabel = user?.username ? `@${user.username}` : this.shortenIdentifier(identity);
    node.title = user?.displayName || displayName || identity;
  }

  private ensureNetworkEdge(
    state: DebugNetworkBuildState,
    kind: DebugNetworkEdgeKind,
    sourceId: string,
    targetId: string,
    timestamp: number
  ): MutableDebugNetworkEdge {
    const edgeId = `${kind}:${sourceId}->${targetId}`;
    const existing = state.edges.get(edgeId);

    if (existing) {
      existing.lastSeen = Math.max(existing.lastSeen, timestamp);
      return existing;
    }

    const edge: MutableDebugNetworkEdge = {
      id: edgeId,
      kind,
      sourceId,
      targetId,
      stateLabel: kind === 'membership' ? 'joined' : '',
      isActive: kind === 'membership',
      pingMs: null,
      lastSeen: timestamp,
      messageTotal: 0,
      messageGroups: new Map()
    };

    state.edges.set(edgeId, edge);

    return edge;
  }

  private recordNetworkMessage(
    edge: MutableDebugNetworkEdge,
    type: string,
    direction: DebugNetworkMessageDirection,
    scope: DebugNetworkMessageScope,
    timestamp: number,
    count: number
  ): void {
    if (NETWORK_IGNORED_MESSAGE_TYPES.has(type))
      return;

    const groupId = `${scope}:${direction}:${type}`;
    const existing = edge.messageGroups.get(groupId);

    edge.lastSeen = Math.max(edge.lastSeen, timestamp);
    edge.messageTotal += count;

    if (existing) {
      existing.count += count;
      existing.lastSeen = Math.max(existing.lastSeen, timestamp);
      return;
    }

    edge.messageGroups.set(groupId, {
      id: groupId,
      scope,
      direction,
      type,
      count,
      lastSeen: timestamp
    });
  }

  private incrementHandshakeStats(
    node: MutableDebugNetworkNode,
    type: string,
    direction: DebugNetworkMessageDirection,
    count: number
  ): void {
    switch (type) {
      case 'offer':
        if (direction === 'outbound')
          node.handshake.offersSent += count;
        else
          node.handshake.offersReceived += count;

        return;

      case 'answer':
        if (direction === 'outbound')
          node.handshake.answersSent += count;
        else
          node.handshake.answersReceived += count;

        return;

      case 'ice_candidate':
        if (direction === 'outbound')
          node.handshake.iceSent += count;
        else
          node.handshake.iceReceived += count;

        return;
    }
  }

  private incrementTextMessageCount(
    node: MutableDebugNetworkNode,
    direction: DebugNetworkMessageDirection,
    count: number
  ): void {
    if (direction === 'outbound') {
      node.textMessages.sent += count;
      return;
    }

    node.textMessages.received += count;
  }

  private recordFileTransferSample(
    node: MutableDebugNetworkNode,
    timestamp: number,
    bytes: number,
    count: number
  ): void {
    if (bytes <= 0 || count <= 0)
      return;

    node.fileTransferSamples.push({
      bytes: bytes * count,
      timestamp
    });

    node.fileTransferSamples = node.fileTransferSamples.filter(
      (sample) => timestamp - sample.timestamp <= NETWORK_FILE_TRANSFER_RATE_WINDOW_MS
    );
  }

  private updateNodeDownloadStats(
    node: MutableDebugNetworkNode,
    stats: { audioMbps?: number | null; videoMbps?: number | null },
    timestamp: number
  ): void {
    if (stats.audioMbps !== undefined)
      node.downloads.audioMbps = this.sanitizeRate(stats.audioMbps);

    if (stats.videoMbps !== undefined)
      node.downloads.videoMbps = this.sanitizeRate(stats.videoMbps);

    node.downloadsUpdatedAt = timestamp;
  }

  private sanitizeRate(value: number | null | undefined): number | null {
    if (typeof value !== 'number' || !Number.isFinite(value) || value < 0)
      return null;

    return Math.round(value * 1000) / 1000;
  }

  private applyVoiceStateToNetworkNode(node: MutableDebugNetworkNode, voiceState: Record<string, unknown> | null): void {
    if (!voiceState)
      return;

    const isConnected = this.getBooleanProperty(voiceState, 'isConnected');
    const isMuted = this.getBooleanProperty(voiceState, 'isMuted');
    const isDeafened = this.getBooleanProperty(voiceState, 'isDeafened');
    const isSpeaking = this.getBooleanProperty(voiceState, 'isSpeaking');

    if (isConnected !== null)
      node.isVoiceConnected = isConnected;

    if (isConnected === false)
      node.streams.audio = 0;

    if (isMuted !== null)
      node.isMuted = isMuted;

    if (isDeafened !== null)
      node.isDeafened = isDeafened;

    if (isSpeaking !== null)
      node.isSpeaking = isSpeaking;
  }

  private isLocalIdentity(state: DebugNetworkBuildState, identity: string): boolean {
    return state.localIds.has(identity);
  }

  private shouldIncludeNetworkEdge(edge: MutableDebugNetworkEdge, now: number): boolean {
    if (edge.kind === 'membership')
      return edge.isActive;

    if (edge.isActive)
      return true;

    return now - edge.lastSeen <= NETWORK_RECENT_EDGE_TTL_MS;
  }

  private finalizeNetworkNode(
    node: MutableDebugNetworkNode,
    state: DebugNetworkBuildState,
    now: number,
    hasActiveEdge: boolean
  ): DebugNetworkNode {
    if (node.kind === 'remote-client' && node.identity)
      this.applyLivePeerMetricsToNetworkNode(node, node.identity, now);

    const isTyping = node.typingExpiresAt !== null && node.typingExpiresAt > now;
    const user = node.identity ? state.userLookup.get(node.identity) : undefined;
    const presentation = this.buildFinalizedNodePresentation(node, state, user, hasActiveEdge);
    const streams = this.buildFinalizedNodeStreams(node);
    const downloads = this.getFreshDownloadStats(node, now);
    const statuses = this.buildFinalizedNodeStatuses(node, streams, isTyping, hasActiveEdge);

    return {
      id: node.id,
      identity: node.identity,
      userId: presentation.userId,
      kind: node.kind,
      label: presentation.label,
      secondaryLabel: presentation.secondaryLabel,
      title: presentation.title,
      statuses,
      isActive: presentation.isActive,
      isVoiceConnected: node.isVoiceConnected,
      isTyping,
      isSpeaking: node.isSpeaking,
      isMuted: node.isMuted,
      isDeafened: node.isDeafened,
      isStreaming: node.isStreaming,
      connectionDrops: node.connectionDrops,
      downloads,
      handshake: { ...node.handshake },
      pingMs: node.pingMs,
      streams,
      textMessages: { ...node.textMessages },
      lastSeen: node.lastSeen
    };
  }

  private buildFinalizedNodePresentation(
    node: MutableDebugNetworkNode,
    state: DebugNetworkBuildState,
    user: User | undefined,
    hasActiveEdge: boolean
  ): FinalizedNodePresentation {
    if (node.kind === 'local-client')
      return this.buildLocalNodePresentation(node, state);

    return this.buildRemoteNodePresentation(node, user, hasActiveEdge);
  }

  private buildLocalNodePresentation(
    node: MutableDebugNetworkNode,
    state: DebugNetworkBuildState
  ): FinalizedNodePresentation {
    return {
      userId: node.userId || state.currentUser?.id || null,
      label: state.currentUser?.displayName || state.currentUser?.username || node.label || 'You',
      secondaryLabel: state.currentUser?.username ? `@${state.currentUser.username}` : 'You',
      title: 'Current client',
      isActive: true
    };
  }

  private buildRemoteNodePresentation(
    node: MutableDebugNetworkNode,
    user: User | undefined,
    hasActiveEdge: boolean
  ): FinalizedNodePresentation {
    return {
      userId: node.userId || user?.id || null,
      label: user?.displayName || user?.username || node.label,
      secondaryLabel: user?.username ? `@${user.username}` : node.secondaryLabel,
      title: node.title,
      isActive: hasActiveEdge || node.isActive
    };
  }

  private buildFinalizedNodeStreams(node: MutableDebugNetworkNode): { audio: number; video: number } {
    return {
      audio: node.streams.audio > 0 ? node.streams.audio : (node.isVoiceConnected ? 1 : 0),
      video: node.streams.video > 0 ? node.streams.video : (node.isStreaming ? 1 : 0)
    };
  }

  private buildFinalizedNodeStatuses(
    node: MutableDebugNetworkNode,
    streams: { audio: number; video: number },
    isTyping: boolean,
    hasActiveEdge: boolean
  ): string[] {
    const statuses: string[] = [];

    if (node.kind === 'local-client' || node.kind === 'remote-client') {
      if (isTyping)
        statuses.push('typing');

      if (node.isSpeaking)
        statuses.push('speaking');

      if (node.isVoiceConnected)
        statuses.push(node.isMuted ? 'mic muted' : 'mic on');

      if (node.isDeafened)
        statuses.push('deafened');

      if (node.isStreaming)
        statuses.push('streaming');

      if (node.pingMs !== null)
        statuses.push(`${node.pingMs} ms`);

      if (streams.audio > 0)
        statuses.push(this.buildStreamStatus(streams.audio, 'voice stream'));

      if (streams.video > 0)
        statuses.push(this.buildStreamStatus(streams.video, 'video stream'));

      if (node.connectionDrops > 0)
        statuses.push(this.buildStreamStatus(node.connectionDrops, 'drop'));

      return statuses;
    }

    if (node.kind === 'signaling-server') {
      statuses.push(hasActiveEdge ? 'connected' : 'idle');
      return statuses;
    }

    if (hasActiveEdge)
      statuses.push('active');

    return statuses;
  }

  private applyLivePeerMetricsToNetworkNode(
    node: MutableDebugNetworkNode,
    identity: string,
    now: number
  ): void {
    const metrics = getDebugNetworkMetricSnapshot(identity);

    if (!metrics)
      return;

    if (metrics.pingMs !== null)
      node.pingMs = metrics.pingMs;

    node.connectionDrops = Math.max(node.connectionDrops, metrics.connectionDrops);
    node.handshake.answersReceived = Math.max(node.handshake.answersReceived, metrics.handshake.answersReceived);
    node.handshake.answersSent = Math.max(node.handshake.answersSent, metrics.handshake.answersSent);
    node.handshake.iceReceived = Math.max(node.handshake.iceReceived, metrics.handshake.iceReceived);
    node.handshake.iceSent = Math.max(node.handshake.iceSent, metrics.handshake.iceSent);
    node.handshake.offersReceived = Math.max(node.handshake.offersReceived, metrics.handshake.offersReceived);
    node.handshake.offersSent = Math.max(node.handshake.offersSent, metrics.handshake.offersSent);
    node.streams.audio = Math.max(node.streams.audio, metrics.streams.audio);
    node.streams.video = Math.max(node.streams.video, metrics.streams.video);
    node.textMessages.received = Math.max(node.textMessages.received, metrics.textMessages.received);
    node.textMessages.sent = Math.max(node.textMessages.sent, metrics.textMessages.sent);

    if (metrics.streams.audio > 0)
      node.isVoiceConnected = true;

    if (metrics.streams.video > 0)
      node.isStreaming = true;

    if (metrics.downloads.audioMbps !== null)
      node.downloads.audioMbps = metrics.downloads.audioMbps;

    if (metrics.downloads.videoMbps !== null)
      node.downloads.videoMbps = metrics.downloads.videoMbps;

    if (metrics.downloads.fileMbps !== null)
      node.downloads.fileMbps = metrics.downloads.fileMbps;

    if (metrics.downloads.updatedAt !== null)
      node.downloadsUpdatedAt = Math.max(node.downloadsUpdatedAt ?? 0, metrics.downloads.updatedAt);

    node.lastSeen = Math.max(node.lastSeen, now);
  }

  private getFreshDownloadStats(node: MutableDebugNetworkNode, now: number): DebugNetworkDownloadStats {
    const hasFreshRtcStats = node.downloadsUpdatedAt !== null && now - node.downloadsUpdatedAt <= NETWORK_DOWNLOAD_STAT_TTL_MS;
    const fileDownloadMbps = this.calculateFileDownloadMbps(node.fileTransferSamples, now) ?? node.downloads.fileMbps;

    return {
      audioMbps: hasFreshRtcStats ? node.downloads.audioMbps : null,
      fileMbps: fileDownloadMbps,
      videoMbps: hasFreshRtcStats ? node.downloads.videoMbps : null
    };
  }

  private calculateFileDownloadMbps(samples: DebugNetworkTransferSample[], now: number): number | null {
    const recentSamples = samples.filter(
      (sample) => now - sample.timestamp <= NETWORK_FILE_TRANSFER_RATE_WINDOW_MS
    );

    if (recentSamples.length === 0)
      return null;

    const totalBytes = recentSamples.reduce((sum, sample) => sum + sample.bytes, 0);
    const earliestTimestamp = recentSamples[0]?.timestamp ?? now;
    const durationMs = Math.max(1_000, now - earliestTimestamp);

    return this.sanitizeRate(totalBytes * 8 / durationMs / 1000);
  }

  private buildStreamStatus(count: number, label: string): string {
    return `${count} ${label}${count === 1 ? '' : 's'}`;
  }

  private finalizeNetworkEdge(
    edge: MutableDebugNetworkEdge,
    nodeLookup: Map<string, DebugNetworkNode>
  ): DebugNetworkEdge | null {
    const sourceNode = nodeLookup.get(edge.sourceId);
    const targetNode = nodeLookup.get(edge.targetId);

    if (!sourceNode || !targetNode)
      return null;

    const messageGroups = Array.from(edge.messageGroups.values())
      .sort((groupA, groupB) => {
        if (groupA.lastSeen !== groupB.lastSeen)
          return groupB.lastSeen - groupA.lastSeen;

        return groupB.count - groupA.count;
      })
      .slice(0, NETWORK_MESSAGE_GROUP_LIMIT)
      .map((group) => ({
        id: group.id,
        scope: group.scope,
        direction: group.direction,
        type: group.type,
        count: group.count,
        lastSeen: group.lastSeen
      }));

    return {
      id: edge.id,
      kind: edge.kind,
      sourceId: edge.sourceId,
      targetId: edge.targetId,
      sourceLabel: sourceNode.label,
      targetLabel: targetNode.label,
      label: this.buildNetworkEdgeLabel(edge),
      stateLabel: edge.stateLabel || (edge.isActive ? 'active' : 'idle'),
      isActive: edge.isActive,
      pingMs: edge.pingMs,
      lastSeen: edge.lastSeen,
      messageTotal: edge.messageTotal,
      messageGroups
    };
  }

  private buildNetworkEdgeLabel(edge: MutableDebugNetworkEdge): string {
    if (edge.kind === 'peer') {
      if (edge.pingMs !== null)
        return `${edge.pingMs} ms`;

      return edge.stateLabel || (edge.isActive ? 'p2p' : 'idle');
    }

    if (edge.kind === 'signaling')
      return edge.stateLabel || (edge.isActive ? 'connected' : 'idle');

    return edge.isActive ? (edge.stateLabel || 'joined') : (edge.stateLabel || 'inactive');
  }

  private compareNetworkEdges(edgeA: MutableDebugNetworkEdge, edgeB: MutableDebugNetworkEdge): number {
    if (edgeA.isActive !== edgeB.isActive)
      return edgeA.isActive ? -1 : 1;

    if (edgeA.kind !== edgeB.kind)
      return this.getNetworkEdgeOrder(edgeA.kind) - this.getNetworkEdgeOrder(edgeB.kind);

    return edgeB.lastSeen - edgeA.lastSeen;
  }

  private getNetworkEdgeOrder(kind: DebugNetworkEdgeKind): number {
    switch (kind) {
      case 'signaling':
        return 0;
      case 'peer':
        return 1;
      case 'membership':
        return 2;
    }
  }

  private compareFinalNetworkNodes(nodeA: DebugNetworkNode, nodeB: DebugNetworkNode): number {
    if (nodeA.kind !== nodeB.kind)
      return this.getNetworkNodeOrder(nodeA.kind) - this.getNetworkNodeOrder(nodeB.kind);

    return nodeA.label.localeCompare(nodeB.label);
  }

  private getNetworkNodeOrder(kind: DebugNetworkNodeKind): number {
    switch (kind) {
      case 'local-client':
        return 0;
      case 'signaling-server':
        return 1;
      case 'app-server':
        return 2;
      case 'remote-client':
        return 3;
    }
  }

  private getSignalingEdgeStateLabel(message: string): string {
    switch (message) {
      case 'Connected to signaling server':
        return 'connected';
      case 'Connecting to signaling server':
      case 'Attempting reconnect':
        return 'connecting';
      case 'Disconnected from signaling server':
        return 'disconnected';
      case 'Signaling socket error':
      case 'Failed to initialize signaling socket':
        return 'error';
      default:
        return 'active';
    }
  }

  private getSignalingHostLabel(url: string): string {
    try {
      return new URL(url).hostname || 'signaling';
    } catch {
      return 'signaling';
    }
  }

  private getSignalingSecondaryLabel(url: string): string {
    try {
      const parsed = new URL(url);

      return `${parsed.protocol}//${parsed.host}`;
    } catch {
      return url;
    }
  }

  private shortenIdentifier(value: string): string {
    if (value.length <= 12)
      return value;

    return `${value.slice(0, 6)}...${value.slice(-4)}`;
  }

  private getEntryPayloadRecord(payload: unknown): Record<string, unknown> | null {
    if (Array.isArray(payload)) {
      for (const value of payload) {
        const record = this.asRecord(value);

        if (record)
          return record;
      }

      return null;
    }

    return this.asRecord(payload);
  }

  private getPayloadField(payload: Record<string, unknown> | null, key: string): unknown {
    if (!payload)
      return undefined;

    if (key in payload)
      return payload[key];

    const nestedPreview = this.asRecord(payload['payloadPreview']);

    return nestedPreview?.[key];
  }

  private getPayloadString(payload: Record<string, unknown> | null, key: string): string | null {
    const value = this.getPayloadField(payload, key);

    return this.normalizeStringValue(value);
  }

  private getPayloadNumber(payload: Record<string, unknown> | null, key: string): number | null {
    const value = this.getPayloadField(payload, key);

    return typeof value === 'number' ? value : null;
  }

  private getPayloadBoolean(payload: Record<string, unknown> | null, key: string): boolean | null {
    const value = this.getPayloadField(payload, key);

    return typeof value === 'boolean' ? value : null;
  }

  private getPayloadRecord(payload: Record<string, unknown> | null, key: string): Record<string, unknown> | null {
    return this.asRecord(this.getPayloadField(payload, key));
  }

  private getPayloadArray(payload: Record<string, unknown> | null, key: string): unknown[] {
    const value = this.getPayloadField(payload, key);

    return Array.isArray(value) ? value : [];
  }

  private getStringProperty(record: Record<string, unknown> | null, key: string): string | null {
    const value = record?.[key];

    return this.normalizeStringValue(value);
  }

  private getBooleanProperty(record: Record<string, unknown> | null, key: string): boolean | null {
    const value = record?.[key];

    return typeof value === 'boolean' ? value : null;
  }

  private getNumberProperty(record: Record<string, unknown> | null, key: string): number | null {
    const value = record?.[key];

    return typeof value === 'number' ? value : null;
  }

  private asRecord(value: unknown): Record<string, unknown> | null {
    if (!value || typeof value !== 'object' || Array.isArray(value))
      return null;

    return value as Record<string, unknown>;
  }

  private normalizeStringValue(value: unknown): string | null {
    if (typeof value !== 'string')
      return null;

    const normalized = value.trim();

    if (!normalized || normalized === 'undefined' || normalized === 'null')
      return null;

    return normalized;
  }
}
