import { parentPort, workerData } from 'worker_threads';
import WebSocket from 'ws';
import { loadConfig } from "../config.js";
import log4js from "log4js";
import dns from 'dns';

// Load configuration
const config = loadConfig();

class WebSocketScannerWorker {
    constructor() {
        this.randomId = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
        this.logger = log4js.getLogger(`WS Scanner #${this.randomId}`);
        this.logger.level = config.server.logLevel;
        this.timeout = 2000; // 2 second timeout for each connection attempt
    }

    async scanRange(startIP, endIP, port, protocol) {
        const start = this.ipToNumber(startIP);
        const end = this.ipToNumber(endIP);
        const foundServices = [];

        this.logger.info(`Scanning ${startIP} - ${endIP} on port: ${port} using: ${protocol}`);

        for (let ip = start; ip <= end; ip++) {
            const currentIP = this.numberToIP(ip);
            const url = `${protocol}://${currentIP}:${port}/websocket`;

            try {
                this.logger.debug(`Checking ${currentIP} for websocket service on port ${port}`);
                const isOpen = await this.checkWebSocket(url);
                if (isOpen) {
                    const hostname = await this.resolveHostname(currentIP);
                    foundServices.push({ ip: currentIP, hostname });
                    this.logger.info(`WebSocket connection successful for ${currentIP}${hostname ? ` (${hostname})` : ''}`);
                    parentPort.postMessage({ type: 'serviceFound', ip: currentIP, hostname });
                } else {
                    this.logger.debug(`WebSocket connection failed for ${currentIP}`);
                }
            } catch (error) {
                // Connection failed, continue scanning
            }

            parentPort.postMessage({ 
                type: 'scanProgress', 
                currentIP,
                increment: 1
            });
        }

        return foundServices;
    }

    async resolveHostname(ip) {
        try {
            const hostnames = await dns.promises.reverse(ip);
            return hostnames[0] || null;
        } catch (error) {
            // Only log errors that aren't ENOTFOUND (which is expected for many IPs)
            if (error.code !== 'ENOTFOUND') {
                this.logger.warn(`Unexpected error resolving hostname for ${ip}: ${error.message}`);
            }
            return null;
        }
    }

    checkWebSocket(url) {
        return new Promise((resolve) => {
            const ws = new WebSocket(url);
            let timeout = setTimeout(() => {
                ws.terminate();
                resolve(false);
            }, this.timeout);

            ws.on('open', () => {
                clearTimeout(timeout);
                ws.close();
                resolve(true);
            });

            ws.on('error', () => {
                clearTimeout(timeout);
                resolve(false);
            });
        });
    }

    ipToNumber(ip) {
        return ip.split('.')
            .reduce((acc, octet) => (acc << 8) + parseInt(octet), 0) >>> 0;
    }

    numberToIP(num) {
        return [
            (num >>> 24) & 255,
            (num >>> 16) & 255,
            (num >>> 8) & 255,
            num & 255
        ].join('.');
    }
}

// Handle messages from the main thread
parentPort.on('message', async (data) => {
    if (data.type === 'scan') {
        const scanner = new WebSocketScannerWorker();
        const results = await scanner.scanRange(data.startIP, data.endIP, data.port, data.protocol);
        parentPort.postMessage({ type: 'scanComplete', results });
    }
}); 