export var ActivityState;
(function (ActivityState) {
    ActivityState["ACTIVE"] = "ACTIVE";
    ActivityState["INACTIVE"] = "INACTIVE";
    ActivityState["DISCONNECTED"] = "DISCONNECTED";
    ActivityState["READY_FOR_TAKEOVER"] = "READY_FOR_TAKEOVER";
})(ActivityState || (ActivityState = {}));
/**
 * Tracks user activity state for lock release decisions.
 * Simple state tracker - no events, just query methods.
 */
export class ActivityTracker {
    logger;
    inactivityThresholdMs;
    _state = ActivityState.ACTIVE;
    _lastActivityTimestamp = Date.now();
    _connectedUserPeerIdsMap = new Map();
    constructor(config) {
        this.logger = config.logger;
        this.inactivityThresholdMs = config.inactivityThresholdMs;
    }
    get wasRecentlyActive() {
        // Check if last active ping was within the recent activity window
        // This is more reliable than checking current state
        const timeSinceLastActivityMs = Date.now() - this._lastActivityTimestamp;
        return timeSinceLastActivityMs < this.inactivityThresholdMs;
    }
    get timeSinceLastActivity() {
        return Date.now() - this._lastActivityTimestamp;
    }
    get connectedUsers() {
        return Array.from(this._connectedUserPeerIdsMap.keys());
    }
    get isDisconnected() {
        return this._state === ActivityState.DISCONNECTED;
    }
    get isReadyForTakeover() {
        return this._state === ActivityState.READY_FOR_TAKEOVER;
    }
    /**
     * Mark user's activity from UI ping with isUserActive=true/false.
     * This is called when the UI sends activity pings.
     */
    markActivity(isUserActive) {
        const currentState = this._state;
        // If user becomes active and was ready for takeover, reset that state
        if (isUserActive && this._state === ActivityState.READY_FOR_TAKEOVER) {
            this.resetReadyForTakeover();
            return;
        }
        // Don't override DISCONNECTED state from UI pings
        if (this._state === ActivityState.DISCONNECTED) {
            return;
        }
        this._state = isUserActive ? ActivityState.ACTIVE : ActivityState.INACTIVE;
        // Only update timestamp when user is actually active
        if (isUserActive) {
            this._lastActivityTimestamp = Date.now();
        }
        if (currentState !== this._state) {
            this.logger.debug(`[activity-tracker] user marked as ${this._state}`);
        }
    }
    /**
     * Mark the lock as ready for takeover due to prolonged inactivity.
     * This happens when the user has been inactive for too long.
     */
    markReadyForTakeover() {
        this._state = ActivityState.READY_FOR_TAKEOVER;
        this.logger.debug("[activity-tracker] lock marked as ready for takeover");
    }
    /**
     * Mark the session as disconnected due to startup timeout when no socket ever connected.
     * This allows lock evaluation to follow the same disconnected/inactive path.
     */
    markDisconnectedDueToStartupTimeout() {
        if (this._connectedUserPeerIdsMap.size > 0) {
            return;
        }
        this._state = ActivityState.DISCONNECTED;
        // Ensure timeout-triggered evaluation treats this as stale activity.
        this._lastActivityTimestamp = Date.now() - this.inactivityThresholdMs;
        this.logger.debug("[activity-tracker] startup connection timeout elapsed, marking as disconnected");
    }
    /**
     * Reset the ready for takeover state when user becomes active again.
     */
    resetReadyForTakeover() {
        if (this._state === ActivityState.READY_FOR_TAKEOVER) {
            this._state = ActivityState.ACTIVE;
            this._lastActivityTimestamp = Date.now();
            this.logger.debug("[activity-tracker] ready for takeover state reset, user is active again");
        }
    }
    /**
     * Add a connected peer for a user
     */
    addConnectedPeerIdToUser(userId, peerId) {
        if (!this._connectedUserPeerIdsMap.has(userId)) {
            this._connectedUserPeerIdsMap.set(userId, new Set([peerId]));
        }
        else {
            this._connectedUserPeerIdsMap.get(userId)?.add(peerId);
        }
        this.logger.debug(`[activity-tracker] added peerId ${peerId} to user ${userId}`);
        // Clear any disconnected or ready for takeover state since we have an active connection
        if (this._state === ActivityState.DISCONNECTED ||
            this._state === ActivityState.READY_FOR_TAKEOVER) {
            this._state = ActivityState.ACTIVE;
            this._lastActivityTimestamp = Date.now();
            this.logger.debug("[activity-tracker] user reconnected, marking as active");
        }
    }
    /**
     * Remove a connected peer for a user
     */
    removeConnectedPeerIdFromUser(userId, peerId) {
        if (this._connectedUserPeerIdsMap.has(userId)) {
            this._connectedUserPeerIdsMap.get(userId)?.delete(peerId);
            this.logger.debug(`[activity-tracker] removed peerId ${peerId} from user ${userId}`);
        }
        if (this._connectedUserPeerIdsMap.get(userId)?.size === 0) {
            this._connectedUserPeerIdsMap.delete(userId);
            this.logger.debug(`[activity-tracker] removed connected user ${userId}`);
        }
        // Check if all peers are disconnected
        if (this._connectedUserPeerIdsMap.size === 0) {
            this._state = ActivityState.DISCONNECTED;
            this.logger.debug("[activity-tracker] all peers disconnected");
        }
    }
}
//# sourceMappingURL=activity-tracker.js.map