import {
  DATA_CHANNEL_STATE_OPEN,
  P2P_TYPE_PING,
  PEER_PING_INTERVAL_MS
} from '../../realtime.constants';
import { WebRTCLogger } from '../../logging/webrtc-logger';
import { PeerConnectionManagerState } from '../shared';

/** Start periodic pings to a peer to measure round-trip latency. */
export function startPingInterval(state: PeerConnectionManagerState, logger: WebRTCLogger, peerId: string): void {
  stopPingInterval(state, peerId);
  sendPing(state, logger, peerId);

  const timer = setInterval(() => sendPing(state, logger, peerId), PEER_PING_INTERVAL_MS);

  state.peerPingTimers.set(peerId, timer);
}

/** Stop the periodic ping for a specific peer. */
export function stopPingInterval(state: PeerConnectionManagerState, peerId: string): void {
  const timer = state.peerPingTimers.get(peerId);

  if (timer) {
    clearInterval(timer);
    state.peerPingTimers.delete(peerId);
  }
}

/** Cancel all active ping timers. */
export function clearAllPingTimers(state: PeerConnectionManagerState): void {
  state.peerPingTimers.forEach((timer) => clearInterval(timer));
  state.peerPingTimers.clear();
}

/** Send a single ping to a peer. */
export function sendPing(state: PeerConnectionManagerState, logger: WebRTCLogger, peerId: string): void {
  const peerData = state.activePeerConnections.get(peerId);

  if (!peerData?.dataChannel || peerData.dataChannel.readyState !== DATA_CHANNEL_STATE_OPEN)
    return;

  const timestamp = performance.now();

  state.pendingPings.set(peerId, timestamp);

  try {
    const payload = JSON.stringify({
      type: P2P_TYPE_PING,
      ts: timestamp
    });

    peerData.dataChannel.send(payload);
    logger.traffic('data-channel', 'outbound', {
      bufferedAmount: peerData.dataChannel.bufferedAmount,
      bytes: new TextEncoder().encode(payload).length,
      channelLabel: peerData.dataChannel.label,
      peerId,
      readyState: peerData.dataChannel.readyState,
      type: P2P_TYPE_PING
    });
  } catch (error) {
    logger.error('[data-channel] Failed to send ping', error, {
      bufferedAmount: peerData.dataChannel.bufferedAmount,
      channelLabel: peerData.dataChannel.label,
      peerId,
      readyState: peerData.dataChannel.readyState,
      ts: timestamp,
      type: P2P_TYPE_PING
    });
  }
}
