import { Subject } from 'rxjs';
import { ChatEvent } from '../../../shared-kernel';
import { WebRTCLogger } from '../logging/webrtc-logger';
import {
  DisconnectedPeerEntry,
  IdentifyCredentials,
  PeerData,
  VoiceStateSnapshot
} from '../realtime.types';

/**
 * Callbacks the PeerConnectionManager needs from the owning service.
 * This keeps the manager decoupled from Angular DI / signals.
 */
export interface PeerConnectionCallbacks {
  /** Send a raw JSON message via the signaling server. */
  sendRawMessage(msg: Record<string, unknown>): void;
  /** Get the current local media stream (mic audio). */
  getLocalMediaStream(): MediaStream | null;
  /** Whether signaling is currently connected. */
  isSignalingConnected(): boolean;
  /** Returns the current voice/screen state snapshot for broadcasting. */
  getVoiceStateSnapshot(): VoiceStateSnapshot;
  /** Returns the identify credentials (oderId + displayName). */
  getIdentifyCredentials(): IdentifyCredentials | null;
  /** Returns the local peer ID. */
  getLocalPeerId(): string;
  /** Whether screen sharing is active. */
  isScreenSharingActive(): boolean;
  /** Whether the local camera is active. */
  isCameraEnabled(): boolean;
  /** Returns the user-configured ICE servers for peer connection creation. */
  getIceServers(): RTCIceServer[];
}

export interface PeerConnectionManagerState {
  activePeerConnections: Map<string, PeerData>;
  remotePeerStreams: Map<string, MediaStream>;
  remotePeerVoiceStreams: Map<string, MediaStream>;
  remotePeerCameraStreams: Map<string, MediaStream>;
  remotePeerScreenShareStreams: Map<string, MediaStream>;
  disconnectedPeerTracker: Map<string, DisconnectedPeerEntry>;
  peerReconnectTimers: Map<string, ReturnType<typeof setInterval>>;
  peerDisconnectGraceTimers: Map<string, ReturnType<typeof setTimeout>>;
  pendingPings: Map<string, number>;
  peerPingTimers: Map<string, ReturnType<typeof setInterval>>;
  peerLatencies: Map<string, number>;
  peerLatencyChanged$: Subject<{ peerId: string; latencyMs: number }>;
  peerNegotiationQueue: Map<string, Promise<void>>;
  peerConnected$: Subject<string>;
  peerDisconnected$: Subject<string>;
  remoteStream$: Subject<{ peerId: string; stream: MediaStream }>;
  messageReceived$: Subject<ChatEvent>;
  connectedPeersChanged$: Subject<string[]>;
  connectedPeersList: string[];
}

export interface PeerConnectionManagerContext {
  readonly logger: WebRTCLogger;
  readonly callbacks: PeerConnectionCallbacks;
  readonly state: PeerConnectionManagerState;
}

export interface RemovePeerOptions {
  preserveReconnectState?: boolean;
}

export interface ConnectionLifecycleHandlers {
  clearPeerDisconnectGraceTimer(peerId: string): void;
  addToConnectedPeers(peerId: string): void;
  clearPeerReconnectTimer(peerId: string): void;
  requestVoiceStateFromPeer(peerId: string): void;
  schedulePeerDisconnectRecovery(peerId: string): void;
  trackDisconnectedPeer(peerId: string): void;
  removePeer(peerId: string, options?: RemovePeerOptions): void;
  schedulePeerReconnect(peerId: string): void;
  handleRemoteTrack(event: RTCTrackEvent, remotePeerId: string): void;
  setupDataChannel(channel: RTCDataChannel, remotePeerId: string): void;
}

export interface NegotiationHandlers {
  createPeerConnection(remotePeerId: string, isInitiator: boolean): PeerData;
}

export interface RecoveryHandlers {
  removePeer(peerId: string, options?: RemovePeerOptions): void;
  createPeerConnection(peerId: string, isInitiator: boolean): PeerData;
  createAndSendOffer(peerId: string): Promise<void>;
}

export function createPeerConnectionManagerState(): PeerConnectionManagerState {
  return {
    activePeerConnections: new Map<string, PeerData>(),
    remotePeerStreams: new Map<string, MediaStream>(),
    remotePeerVoiceStreams: new Map<string, MediaStream>(),
    remotePeerCameraStreams: new Map<string, MediaStream>(),
    remotePeerScreenShareStreams: new Map<string, MediaStream>(),
    disconnectedPeerTracker: new Map<string, DisconnectedPeerEntry>(),
    peerReconnectTimers: new Map<string, ReturnType<typeof setInterval>>(),
    peerDisconnectGraceTimers: new Map<string, ReturnType<typeof setTimeout>>(),
    pendingPings: new Map<string, number>(),
    peerPingTimers: new Map<string, ReturnType<typeof setInterval>>(),
    peerLatencies: new Map<string, number>(),
    peerLatencyChanged$: new Subject<{ peerId: string; latencyMs: number }>(),
    peerNegotiationQueue: new Map<string, Promise<void>>(),
    peerConnected$: new Subject<string>(),
    peerDisconnected$: new Subject<string>(),
    remoteStream$: new Subject<{ peerId: string; stream: MediaStream }>(),
    messageReceived$: new Subject<ChatEvent>(),
    connectedPeersChanged$: new Subject<string[]>(),
    connectedPeersList: []
  };
}
