import { PeerConnection } from "./peer-connection.js";
export class DataChannelProvider {
    constructor(options) {
        this.options = options;
        this.Connections = new Map();
        this.factory = user => (username) => {
            const connection = new RTCPeerConnection({
                ...DataChannelProvider.defaultOptions,
                ...this.options
            });
            connection.addEventListener('close', () => this.Connections.delete(username));
            this.listenIce(connection, user);
            return connection;
        };
        globalThis.addEventListener('beforeunload', () => this.dispose());
    }
    async withOffer(user, signal, onPeerConnection) {
        if (signal.type !== 'offer')
            return;
        const peerConnection = this.Connections.getOrAdd(user.user, this.factory(user));
        // Send any ice candidates to the other peer.
        console.log('get offer', signal.sdp);
        await peerConnection.setRemoteDescription(signal);
        const answer = await peerConnection.createAnswer();
        await peerConnection.setLocalDescription(answer);
        console.log('send answer', answer.sdp);
        user.signaling.sendSignal({
            type: "signal",
            signal: answer,
            to: user.user
        });
        peerConnection.addEventListener('datachannel', e => {
            // if (e.signal.type !== 'datachannel') {
            //     return
            // }
            // const dataChannel = peerConnection.createDataChannel('chat', {
            //     ordered: true,
            //     id: 0
            // })
            // console.log('create channel', e.signal.id);
            onPeerConnection(new PeerConnection(e.channel, user), e.channel.label.split('-').pop());
        });
        return peerConnection;
        //
        // const event = await fromFirstEvent(peerConnection, 'datachannel') as RTCDataChannelEvent;
        // return event.channel;
    }
    async initiate(user, room, currentUser) {
        const peerConnection = this.Connections.getOrAdd(user.user, this.factory(user));
        peerConnection.addEventListener('negotiationneeded', async (e) => {
            const offer = await peerConnection.createOffer();
            await peerConnection.setLocalDescription(offer);
            console.log('init offer', offer.sdp);
            user.signaling.sendSignal({
                type: "signal",
                signal: offer,
                to: user.user
            });
            const answer = await fromFirstEvent(user.signaling, 'signal');
            if (!(answer.from.user == user.user && answer.signal.type == 'answer')) {
                throw new Error();
            }
            console.log('get answer', answer.signal.sdp);
            await peerConnection.setRemoteDescription(answer.signal);
            // return peerConnection;
        }, {
            once: true
        });
        // const id = Math.random();
        // Send any ice candidates to the other peer.
        const dataChannel = peerConnection.createDataChannel(`${user.user}-${room}`);
        // await fromFirstEvent(peerConnection, 'negotiationneeded');
        // console.log('create channel', id);
        // user.signaling.sendSignal({
        //     type: 'signal',
        //     to: user.user,
        //     signal: {
        //         type: "datachannel",
        //         room: room,
        //         id: id,
        //
        //     }
        // })
        // if (peerConnection.)
        //     return dataChannel;
        await fromFirstEvent(dataChannel, 'open');
        return dataChannel;
    }
    listenIce(peerConnection, user) {
        peerConnection.addEventListener('icecandidate', event => user.signaling.sendSignal({
            type: "signal",
            signal: {
                type: "candidate",
                candidate: event.candidate
            },
            to: user.user
        }));
        user.signaling.on('signal', event => {
            if (event.from.user == user.user && event.signal.type == 'candidate') {
                peerConnection.addIceCandidate(event.signal.candidate);
            }
        });
    }
    async getConnection(user, room, currentUser) {
        const dc = await this.initiate(user, room, currentUser);
        if (!dc)
            debugger;
        return new PeerConnection(dc, user);
    }
    dispose() {
        for (let connection of this.Connections.values()) {
            connection.close();
        }
    }
}
DataChannelProvider.defaultOptions = {
    iceServers: [{
            urls: [
                'stun:stun.l.google.com:19302',
                'stun:global.stun.twilio.com:3478'
            ]
        }],
};
export function fromFirstEvent(target, eventName, options) {
    if ('addEventListener' in target) {
        return new Promise(resolve => target.addEventListener(eventName, resolve, {
            once: true,
            ...options
        }));
    }
    else if ('once' in target) {
        return new Promise(resolve => target.once(eventName, resolve));
    }
}
//# sourceMappingURL=data-channel-provider.js.map