"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SessionManager = void 0;
/**
 * Manages sessions for peers, allowing multiple concurrent sessions
 * per identity key. Primary lookup is always by `sessionNonce`.
 */
class SessionManager {
    constructor() {
        this.sessionNonceToSession = new Map();
        this.identityKeyToNonces = new Map();
    }
    /**
     * Adds a session to the manager, associating it with its sessionNonce,
     * and also with its peerIdentityKey (if any).
     *
     * This does NOT overwrite existing sessions for the same peerIdentityKey,
     * allowing multiple concurrent sessions for the same peer.
     *
     * @param {PeerSession} session - The peer session to add.
     */
    addSession(session) {
        if (typeof session.sessionNonce !== 'string') {
            throw new TypeError('Invalid session: sessionNonce is required to add a session.');
        }
        // Use the sessionNonce as the primary key
        this.sessionNonceToSession.set(session.sessionNonce, session);
        // Also track it by identity key if present
        if (typeof session.peerIdentityKey === 'string') {
            let nonces = this.identityKeyToNonces.get(session.peerIdentityKey);
            if (nonces == null) {
                nonces = new Set();
                this.identityKeyToNonces.set(session.peerIdentityKey, nonces);
            }
            nonces.add(session.sessionNonce);
        }
    }
    /**
     * Updates a session in the manager (primarily by re-adding it),
     * ensuring we record the latest data (e.g., isAuthenticated, lastUpdate, etc.).
     *
     * @param {PeerSession} session - The peer session to update.
     */
    updateSession(session) {
        // Remove the old references (if any) and re-add
        this.removeSession(session);
        this.addSession(session);
    }
    /**
     * Retrieves a session based on a given identifier, which can be:
     *  - A sessionNonce, or
     *  - A peerIdentityKey.
     *
     * If it is a `sessionNonce`, returns that exact session.
     * If it is a `peerIdentityKey`, returns the "best" (e.g. most recently updated,
     * authenticated) session associated with that peer, if any.
     *
     * @param {string} identifier - The identifier for the session (sessionNonce or peerIdentityKey).
     * @returns {PeerSession | undefined} - The matching peer session, or undefined if not found.
     */
    getSession(identifier) {
        // Check if this identifier is directly a sessionNonce
        const direct = this.sessionNonceToSession.get(identifier);
        if (direct != null) {
            return direct;
        }
        // Otherwise, interpret the identifier as an identity key
        const nonces = this.identityKeyToNonces.get(identifier);
        if ((nonces == null) || nonces.size === 0) {
            return undefined;
        }
        // Pick the "best" session. One sensible approach:
        // - Choose an authenticated session if available
        // - Among them, pick the most recently updated
        let best;
        for (const nonce of nonces) {
            const s = this.sessionNonceToSession.get(nonce);
            if (s == null)
                continue;
            // We can prefer authenticated sessions
            if (best == null) {
                best = s;
            }
            else if ((s.lastUpdate ?? 0) > (best.lastUpdate ?? 0)) {
                best = s;
            }
        }
        // Optionally, you could also filter out isAuthenticated===false if you only want
        // an authenticated session. But for our usage, let's return the latest any session.
        return best;
    }
    /**
     * Removes a session from the manager by clearing all associated identifiers.
     *
     * @param {PeerSession} session - The peer session to remove.
     */
    removeSession(session) {
        if (typeof session.sessionNonce === 'string') {
            this.sessionNonceToSession.delete(session.sessionNonce);
        }
        if (typeof session.peerIdentityKey === 'string') {
            const nonces = this.identityKeyToNonces.get(session.peerIdentityKey);
            if (nonces != null) {
                nonces.delete(session.sessionNonce ?? '');
                if (nonces.size === 0) {
                    this.identityKeyToNonces.delete(session.peerIdentityKey);
                }
            }
        }
    }
    /**
     * Checks if a session exists for a given identifier (either sessionNonce or identityKey).
     *
     * @param {string} identifier - The identifier to check.
     * @returns {boolean} - True if the session exists, false otherwise.
     */
    hasSession(identifier) {
        const direct = this.sessionNonceToSession.has(identifier);
        if (direct)
            return true;
        // if not directly a nonce, interpret as identityKey
        const nonces = this.identityKeyToNonces.get(identifier);
        return (nonces != null) && nonces.size > 0;
    }
}
exports.SessionManager = SessionManager;
//# sourceMappingURL=SessionManager.js.map