'use strict';

var EventBus = require('../core/EventBus.js');

/**
 * MultiplayerTransport — abstract transport layer for game multiplayer.
 *
 * Multiple implementations can be plugged in:
 *  - LocalTransport  (in-memory, couch co-op / testing)
 *  - SignalRTransport (real-time via ASP.NET SignalR)
 *  - WebRTCTransport  (peer-to-peer via PeerManager from ./network)
 *
 * For raw WebRTC, see PeerManager in network/Networking.ts.
 */
/* ── LocalTransport (in-memory, same-tab) ──────────────────────── */
class LocalTransport {
    constructor() {
        this.state = "disconnected";
        this.bus = new EventBus.EventBus();
        this.stateListeners = [];
    }
    async connect() { this.setState("connected"); }
    disconnect() { this.setState("disconnected"); }
    send(msg) {
        // Echo locally (useful for testing, couch co-op)
        this.bus.emit(msg.type, msg);
    }
    on(type, handler) { this.bus.on(type, handler); }
    off(type, handler) { this.bus.off(type, handler); }
    onStateChange(handler) { this.stateListeners.push(handler); }
    setState(s) { this.state = s; for (const fn of this.stateListeners)
        fn(s); }
}
/* ── SignalRTransport ──────────────────────────────────────────── */
/**
 * SignalR-based transport.
 *
 * Requires `@microsoft/signalr` to be installed as a peer dependency.
 * Connection is established to `url` (e.g. `/hubs/game`).
 *
 * Hub server methods expected:
 *   CreateRoom, JoinRoom, LeaveRoom, SendGameMessage,
 *   StartMatchmaking, CancelMatchmaking
 *
 * Client-invoked events:
 *   GameMessage, RoomJoined, RoomLeft, PlayerJoined, PlayerLeft,
 *   MatchFound, Error
 */
class SignalRTransport {
    constructor(options) {
        this.state = "disconnected";
        this.connection = null; // HubConnection from @microsoft/signalr
        this.bus = new EventBus.EventBus();
        this.stateListeners = [];
        this.tokenFactory = options === null || options === void 0 ? void 0 : options.accessTokenFactory;
    }
    async connect(url) {
        this.setState("connecting");
        try {
            // Dynamic import so @microsoft/signalr is optional
            const signalR = await Promise.resolve().then(function () { return require('../node_modules/@microsoft/signalr/dist/esm/index.js'); });
            let builder = new signalR.HubConnectionBuilder()
                .withUrl(url, this.tokenFactory ? { accessTokenFactory: this.tokenFactory } : {})
                .withAutomaticReconnect([0, 1000, 2000, 5000, 10000, 30000]);
            this.connection = builder.build();
            // Forward hub events to bus
            const hubEvents = ["GameMessage", "RoomJoined", "RoomLeft", "PlayerJoined", "PlayerLeft", "MatchFound", "Error"];
            for (const evt of hubEvents) {
                this.connection.on(evt, (payload) => {
                    const msg = { type: evt, payload, timestamp: Date.now() };
                    this.bus.emit(evt, msg);
                });
            }
            this.connection.onreconnecting(() => this.setState("reconnecting"));
            this.connection.onreconnected(() => this.setState("connected"));
            this.connection.onclose(() => this.setState("disconnected"));
            await this.connection.start();
            this.setState("connected");
        }
        catch (_a) {
            this.setState("disconnected");
            throw new Error("SignalR connection failed");
        }
    }
    disconnect() {
        var _a;
        (_a = this.connection) === null || _a === void 0 ? void 0 : _a.stop();
        this.connection = null;
        this.setState("disconnected");
    }
    send(msg) {
        var _a;
        (_a = this.connection) === null || _a === void 0 ? void 0 : _a.invoke("SendGameMessage", msg.type, msg.payload);
    }
    /** Hub server invocations */
    async invoke(method, ...args) {
        var _a;
        return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.invoke(method, ...args);
    }
    on(type, handler) { this.bus.on(type, handler); }
    off(type, handler) { this.bus.off(type, handler); }
    onStateChange(handler) { this.stateListeners.push(handler); }
    setState(s) { this.state = s; for (const fn of this.stateListeners)
        fn(s); }
}

exports.LocalTransport = LocalTransport;
exports.SignalRTransport = SignalRTransport;
//# sourceMappingURL=MultiplayerTransport.js.map
