"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.configureWsClient = configureWsClient;
exports.queuePattern = queuePattern;
exports.streamPatterns = streamPatterns;
exports.startStreaming = startStreaming;
exports.stopStreaming = stopStreaming;
exports.isStreamingConnected = isStreamingConnected;
exports.getPendingBatchSize = getPendingBatchSize;
const ws_1 = __importDefault(require("ws"));
const WS_URL = process.env.CELL_WS_URL || 'ws://localhost:9878';
const BATCH_INTERVAL_MS = 5000;
const MAX_BATCH_SIZE = 50;
const RECONNECT_BASE_MS = 1000;
const RECONNECT_MAX_MS = 30000;
const PING_INTERVAL_MS = 30000;
let ws = null;
let deviceId = 'unknown';
let reconnectAttempt = 0;
let reconnectTimer = null;
let pingTimer = null;
let batchTimer = null;
let isConnected = false;
let isEnabled = true;
const pendingBatch = [];
let currentLanguage = 'typescript';
let currentFramework = 'unknown';
function configureWsClient(config) {
    deviceId = config.deviceId;
    if (config.language)
        currentLanguage = config.language;
    if (config.framework)
        currentFramework = config.framework;
    if (config.enabled !== undefined)
        isEnabled = config.enabled;
}
function getReconnectDelay() {
    const delay = RECONNECT_BASE_MS * Math.pow(2, reconnectAttempt);
    return Math.min(delay, RECONNECT_MAX_MS);
}
function connect() {
    if (!isEnabled)
        return;
    if (ws && (ws.readyState === ws_1.default.OPEN || ws.readyState === ws_1.default.CONNECTING))
        return;
    try {
        ws = new ws_1.default(WS_URL);
        ws.on('open', () => {
            isConnected = true;
            reconnectAttempt = 0;
            ws.send(JSON.stringify({
                type: 'identity',
                deviceId,
                language: currentLanguage,
                framework: currentFramework,
            }));
            startPing();
        });
        ws.on('message', (raw) => {
            try {
                const msg = JSON.parse(raw.toString());
                if (msg.type === 'identity_ack') {
                    flushBatch();
                    startBatchTimer();
                }
                if (msg.type === 'pong') {
                }
            }
            catch { }
        });
        ws.on('close', () => {
            isConnected = false;
            cleanup();
            scheduleReconnect();
        });
        ws.on('error', () => {
            isConnected = false;
            cleanup();
            scheduleReconnect();
        });
    }
    catch {
        scheduleReconnect();
    }
}
function scheduleReconnect() {
    if (reconnectTimer)
        return;
    const delay = getReconnectDelay();
    reconnectAttempt++;
    reconnectTimer = setTimeout(() => {
        reconnectTimer = null;
        connect();
    }, delay);
}
function startPing() {
    stopPing();
    pingTimer = setInterval(() => {
        if (ws && ws.readyState === ws_1.default.OPEN) {
            ws.send(JSON.stringify({ type: 'ping' }));
        }
    }, PING_INTERVAL_MS);
}
function stopPing() {
    if (pingTimer) {
        clearInterval(pingTimer);
        pingTimer = null;
    }
}
function startBatchTimer() {
    stopBatchTimer();
    batchTimer = setInterval(() => {
        flushBatch();
    }, BATCH_INTERVAL_MS);
}
function stopBatchTimer() {
    if (batchTimer) {
        clearInterval(batchTimer);
        batchTimer = null;
    }
}
function cleanup() {
    stopPing();
    stopBatchTimer();
}
function flushBatch() {
    if (pendingBatch.length === 0)
        return;
    const batch = pendingBatch.splice(0, MAX_BATCH_SIZE);
    const payload = {
        type: 'patterns',
        patterns: batch,
        language: currentLanguage,
        framework: currentFramework,
        deviceId,
    };
    if (ws && ws.readyState === ws_1.default.OPEN) {
        try {
            ws.send(JSON.stringify(payload));
        }
        catch {
            pendingBatch.unshift(...batch);
        }
    }
    else {
        pendingBatch.unshift(...batch);
    }
}
function queuePattern(pattern) {
    if (!isEnabled)
        return;
    pendingBatch.push(pattern);
    if (pendingBatch.length >= MAX_BATCH_SIZE) {
        flushBatch();
    }
}
function streamPatterns(patterns) {
    if (!isEnabled || patterns.length === 0)
        return;
    for (const p of patterns) {
        queuePattern({
            patternId: p.patternId,
            category: p.category,
            description: p.description,
            from: p.from,
            to: p.to,
            signals: {
                positive: p.signals.positive,
                negative: p.signals.negative,
            },
        });
    }
}
function startStreaming() {
    isEnabled = true;
    connect();
}
function stopStreaming() {
    isEnabled = false;
    cleanup();
    if (reconnectTimer) {
        clearTimeout(reconnectTimer);
        reconnectTimer = null;
    }
    if (ws) {
        try {
            ws.close();
        }
        catch { }
        ws = null;
    }
    isConnected = false;
}
function isStreamingConnected() {
    return isConnected;
}
function getPendingBatchSize() {
    return pendingBatch.length;
}
//# sourceMappingURL=ws-client.js.map