/**
 * V3.11 acceptance criterion: TURN-relay påtvinger relay-modus.
 *
 * We can't do real ICE in the memory factory, but we CAN verify that the
 * RTCConfiguration we pass to the underlying factory carries the
 * `iceTransportPolicy: 'relay'` flag through unchanged when the
 * application configures a TURN-only setup. This guarantees a real
 * RTCPeerConnection adapter (browser / wrtc / node-datachannel) will
 * reject all non-relay candidate pairs as the spec requires.
 */
import { afterEach, describe, expect, it } from 'bun:test';
import { MemoryShadeBridge, WebRtcSignalingChannel } from '../src/signaling.js';
import { WebRtcConnectionManager } from '../src/manager.js';
import {
  DEFAULT_STUN_SERVERS,
  type IDataChannel,
  type IPeerConnection,
  type IRtcFactory,
  type ShadeIceCandidate,
  type ShadeRtcConfig,
  type ShadeRtcConnectionState,
  type ShadeSessionDescription,
} from '../src/types.js';
import { MemoryRtcFactory } from '../src/memory-rtc.js';

afterEach(() => {
  MemoryRtcFactory.reset();
});

class CapturingFactory implements IRtcFactory {
  configs: ShadeRtcConfig[] = [];
  constructor(private readonly inner: IRtcFactory) {}
  createPeerConnection(config: ShadeRtcConfig): IPeerConnection {
    this.configs.push(config);
    return this.inner.createPeerConnection(config);
  }
}

describe('TURN-relay configuration plumbing', () => {
  it('passes iceServers + iceTransportPolicy through to the underlying RTCConfiguration', async () => {
    const turnServers = [
      {
        urls: 'turn:turn.example.com:3478',
        username: 'shade',
        credential: 'secret',
      },
    ];
    const inner = new MemoryRtcFactory();
    const factory = new CapturingFactory(inner);

    const { a, b } = MemoryShadeBridge.linked('alice', 'bob');
    const aliceSig = new WebRtcSignalingChannel(a);
    const bobSig = new WebRtcSignalingChannel(b);
    const alice = new WebRtcConnectionManager({
      factory,
      signaling: aliceSig,
      config: { iceServers: turnServers, iceTransportPolicy: 'relay' },
    });
    const bob = new WebRtcConnectionManager({
      factory,
      signaling: bobSig,
      config: { iceServers: turnServers, iceTransportPolicy: 'relay' },
      receiver: {
        async onChunk() {
          return { lastSeq: 0 };
        },
        async onResumeQuery() {
          return null;
        },
      },
    });

    await alice.getOrCreate('bob');

    // Both sides created at least one PC; each call's config should carry
    // the TURN-only policy verbatim.
    expect(factory.configs.length).toBeGreaterThanOrEqual(2);
    for (const c of factory.configs) {
      expect(c.iceTransportPolicy).toBe('relay');
      expect(c.iceServers).toEqual(turnServers);
    }

    alice.destroy();
    bob.destroy();
  });

  it('falls back to default public STUN when no iceServers are supplied', async () => {
    const inner = new MemoryRtcFactory();
    const factory = new CapturingFactory(inner);
    const { a, b } = MemoryShadeBridge.linked('alice', 'bob');
    const alice = new WebRtcConnectionManager({
      factory,
      signaling: new WebRtcSignalingChannel(a),
      defaultStunServers: DEFAULT_STUN_SERVERS,
    });
    const bob = new WebRtcConnectionManager({
      factory,
      signaling: new WebRtcSignalingChannel(b),
      defaultStunServers: DEFAULT_STUN_SERVERS,
      receiver: {
        async onChunk() {
          return { lastSeq: 0 };
        },
        async onResumeQuery() {
          return null;
        },
      },
    });
    await alice.getOrCreate('bob');
    for (const c of factory.configs) {
      expect(c.iceServers).toEqual(DEFAULT_STUN_SERVERS);
    }
    alice.destroy();
    bob.destroy();
  });
});
