/**
 * Protocol Detector
 *
 * Simplified protocol detection using the new architecture
 */
import { TlsDetector } from './detectors/tls-detector.js';
import { HttpDetector } from './detectors/http-detector.js';
import { DetectionFragmentManager } from './utils/fragment-manager.js';
/**
 * Main protocol detector class
 */
export class ProtocolDetector {
    constructor() {
        this.connectionProtocols = new Map();
        this.fragmentManager = new DetectionFragmentManager();
        this.tlsDetector = new TlsDetector();
        this.httpDetector = new HttpDetector(this.fragmentManager);
    }
    static getInstance() {
        if (!this.instance) {
            this.instance = new ProtocolDetector();
        }
        return this.instance;
    }
    /**
     * Detect protocol from buffer data
     */
    static async detect(buffer, options) {
        return this.getInstance().detectInstance(buffer, options);
    }
    async detectInstance(buffer, options) {
        // Quick sanity check
        if (!buffer || buffer.length === 0) {
            return {
                protocol: 'unknown',
                connectionInfo: { protocol: 'unknown' },
                isComplete: true
            };
        }
        // Try TLS detection first (more specific)
        if (this.tlsDetector.canHandle(buffer)) {
            const tlsResult = this.tlsDetector.detect(buffer, options);
            if (tlsResult) {
                return tlsResult;
            }
        }
        // Try HTTP detection
        if (this.httpDetector.canHandle(buffer)) {
            const httpResult = this.httpDetector.detect(buffer, options);
            if (httpResult) {
                return httpResult;
            }
        }
        // Neither TLS nor HTTP
        return {
            protocol: 'unknown',
            connectionInfo: { protocol: 'unknown' },
            isComplete: true
        };
    }
    /**
     * Detect protocol with connection tracking for fragmented data
     * @deprecated Use detectWithContext instead
     */
    static async detectWithConnectionTracking(buffer, connectionId, options) {
        // Convert connection ID to context
        const context = {
            id: connectionId,
            sourceIp: 'unknown',
            sourcePort: 0,
            destIp: 'unknown',
            destPort: 0,
            timestamp: Date.now()
        };
        return this.getInstance().detectWithContextInstance(buffer, context, options);
    }
    /**
     * Detect protocol with connection context for fragmented data
     */
    static async detectWithContext(buffer, context, options) {
        return this.getInstance().detectWithContextInstance(buffer, context, options);
    }
    async detectWithContextInstance(buffer, context, options) {
        // Quick sanity check
        if (!buffer || buffer.length === 0) {
            return {
                protocol: 'unknown',
                connectionInfo: { protocol: 'unknown' },
                isComplete: true
            };
        }
        const connectionId = DetectionFragmentManager.createConnectionId(context);
        // Check if we already know the protocol for this connection
        const knownProtocol = this.connectionProtocols.get(connectionId);
        if (knownProtocol === 'http') {
            const result = this.httpDetector.detectWithContext(buffer, context, options);
            if (result) {
                if (result.isComplete) {
                    this.connectionProtocols.delete(connectionId);
                }
                return result;
            }
        }
        else if (knownProtocol === 'tls') {
            // Handle TLS with fragment accumulation
            const handler = this.fragmentManager.getHandler('tls');
            const fragmentResult = handler.addFragment(connectionId, buffer);
            if (fragmentResult.error) {
                handler.complete(connectionId);
                this.connectionProtocols.delete(connectionId);
                return {
                    protocol: 'unknown',
                    connectionInfo: { protocol: 'unknown' },
                    isComplete: true
                };
            }
            const result = this.tlsDetector.detect(fragmentResult.buffer, options);
            if (result) {
                if (result.isComplete) {
                    handler.complete(connectionId);
                    this.connectionProtocols.delete(connectionId);
                }
                return result;
            }
        }
        // If we don't know the protocol yet, try to detect it
        if (!knownProtocol) {
            // First peek to determine protocol type
            if (this.tlsDetector.canHandle(buffer)) {
                this.connectionProtocols.set(connectionId, 'tls');
                // Handle TLS with fragment accumulation
                const handler = this.fragmentManager.getHandler('tls');
                const fragmentResult = handler.addFragment(connectionId, buffer);
                if (fragmentResult.error) {
                    handler.complete(connectionId);
                    this.connectionProtocols.delete(connectionId);
                    return {
                        protocol: 'unknown',
                        connectionInfo: { protocol: 'unknown' },
                        isComplete: true
                    };
                }
                const result = this.tlsDetector.detect(fragmentResult.buffer, options);
                if (result) {
                    if (result.isComplete) {
                        handler.complete(connectionId);
                        this.connectionProtocols.delete(connectionId);
                    }
                    return result;
                }
            }
            if (this.httpDetector.canHandle(buffer)) {
                this.connectionProtocols.set(connectionId, 'http');
                const result = this.httpDetector.detectWithContext(buffer, context, options);
                if (result) {
                    if (result.isComplete) {
                        this.connectionProtocols.delete(connectionId);
                    }
                    return result;
                }
            }
        }
        // Can't determine protocol
        return {
            protocol: 'unknown',
            connectionInfo: { protocol: 'unknown' },
            isComplete: false,
            bytesNeeded: Math.max(this.tlsDetector.getMinimumBytes(), this.httpDetector.getMinimumBytes())
        };
    }
    /**
     * Clean up resources
     */
    static cleanup() {
        this.getInstance().cleanupInstance();
    }
    cleanupInstance() {
        this.fragmentManager.cleanup();
    }
    /**
     * Destroy detector instance
     */
    static destroy() {
        this.getInstance().destroyInstance();
        this.instance = null;
    }
    destroyInstance() {
        this.fragmentManager.destroy();
        this.connectionProtocols.clear();
    }
    /**
     * Clean up old connection tracking entries
     *
     * @param _maxAge Maximum age in milliseconds (default: 30 seconds)
     */
    static cleanupConnections(_maxAge = 30000) {
        // Cleanup is now handled internally by the fragment manager
        this.getInstance().fragmentManager.cleanup();
    }
    /**
     * Clean up fragments for a specific connection
     */
    static cleanupConnection(context) {
        const instance = this.getInstance();
        const connectionId = DetectionFragmentManager.createConnectionId(context);
        // Clean up both TLS and HTTP fragments for this connection
        instance.fragmentManager.getHandler('tls').complete(connectionId);
        instance.fragmentManager.getHandler('http').complete(connectionId);
        // Remove from connection protocols tracking
        instance.connectionProtocols.delete(connectionId);
    }
    /**
     * Extract domain from connection info
     */
    static extractDomain(connectionInfo) {
        return connectionInfo.domain || connectionInfo.sni || connectionInfo.host;
    }
    /**
     * Create a connection ID from connection parameters
     * @deprecated Use createConnectionContext instead
     */
    static createConnectionId(params) {
        // If socketId is provided, use it
        if (params.socketId) {
            return params.socketId;
        }
        // Otherwise create from connection tuple
        const { sourceIp = 'unknown', sourcePort = 0, destIp = 'unknown', destPort = 0 } = params;
        return `${sourceIp}:${sourcePort}-${destIp}:${destPort}`;
    }
    /**
     * Create a connection context from parameters
     */
    static createConnectionContext(params) {
        return {
            id: params.socketId,
            sourceIp: params.sourceIp || 'unknown',
            sourcePort: params.sourcePort || 0,
            destIp: params.destIp || 'unknown',
            destPort: params.destPort || 0,
            timestamp: Date.now()
        };
    }
}
//# sourceMappingURL=data:application/json;base64, 