/**
 * Peer Auto-Discovery via mDNS (Bonjour/Avahi)
 *
 * When a master starts serving, it advertises itself on the LAN via mDNS.
 * Other Clawx masters automatically discover and register peers.
 *
 * Service type: _clawx._tcp
 * TXT records: id, name, version
 */
import { log } from '../utils/logger.js';
import { AgentRegistryManager } from './agent-registry.js';
const SERVICE_TYPE = 'clawx';
const CLAWX_VERSION = '1';
let bonjourInstance = null;
let publishedService = null;
let browser = null;
/**
 * Start advertising this master on the LAN and browsing for other masters.
 * Safe to call if mDNS is unavailable — logs a warning and returns false.
 */
export async function startDiscovery(config) {
    try {
        // Suppress DeprecationWarning from bonjour-service ("Calling start() is no longer necessary")
        const originalEmit = process.emit;
        process.emit = function (event, ...args) {
            if (event === 'warning' && args[0]?.name === 'DeprecationWarning' && args[0]?.message?.includes('start()')) {
                return false;
            }
            return originalEmit.apply(process, [event, ...args]);
        };
        const { Bonjour } = await import('bonjour-service');
        bonjourInstance = new Bonjour();
        // Publish our service
        // bonjour-service has two quirks we suppress:
        // 1. DeprecationWarning emitted via process.emit (handled above)
        // 2. "Service name already in use" logged via console.log(new Error(...)) in registry.js
        const originalLog = console.log;
        console.log = function (...args) {
            if (args[0] instanceof Error && args[0].message?.includes('already in use')) {
                log.debug('mDNS: service name already in use on network (previous session)');
                return;
            }
            originalLog.apply(console, args);
        };
        publishedService = bonjourInstance.publish({
            name: `clawx-${config.name}`,
            type: SERVICE_TYPE,
            port: config.port,
            txt: {
                id: config.id,
                name: config.name,
                version: CLAWX_VERSION,
            },
        });
        // Restore original emit and console.log after publish
        // (keep console.log patched briefly — the "already in use" callback fires async)
        setTimeout(() => {
            console.log = originalLog;
        }, 5000);
        process.emit = originalEmit;
        log.info(`mDNS: advertising ${config.name} on port ${config.port}`);
        // Browse for other Clawx masters
        browser = bonjourInstance.find({ type: SERVICE_TYPE }, (service) => {
            handleDiscoveredService(service, config.id);
        });
        return true;
    }
    catch (error) {
        log.debug('mDNS discovery unavailable:', error instanceof Error ? error.message : String(error));
        return false;
    }
}
/**
 * Handle a discovered mDNS service — register as a peer if it's a different master.
 */
function handleDiscoveredService(service, selfId) {
    try {
        const txt = service.txt || {};
        const peerId = txt.id;
        const peerName = txt.name || service.name?.replace(/^clawx-/, '') || 'unknown';
        // Skip self
        if (peerId === selfId)
            return;
        // Get the first IPv4 address
        const rawAddresses = (service.addresses && service.addresses.length > 0)
            ? service.addresses
            : (service.referer?.address ? [service.referer.address] : []);
        const ipv4 = rawAddresses.find((a) => !a.includes(':')) || rawAddresses[0];
        if (!ipv4) {
            log.debug(`mDNS: discovered ${peerName} but no usable address`);
            return;
        }
        const port = service.port;
        const endpoint = `http://${ipv4}:${port}`;
        log.info(`mDNS: discovered peer "${peerName}" at ${endpoint}`);
        // Register in registry if not already present
        const registry = new AgentRegistryManager();
        const allAgents = registry.getAgents();
        // Skip if any existing agent already has this endpoint (avoid duplicates)
        const existingByEndpoint = allAgents.find(a => a.endpoint === endpoint && a.type === 'remote');
        if (existingByEndpoint) {
            // Just update heartbeat to keep it fresh
            existingByEndpoint.status = 'idle';
            existingByEndpoint.lastHeartbeat = Date.now();
            registry.upsertAgent(existingByEndpoint);
            registry.save();
            log.debug(`mDNS: peer at ${endpoint} already registered as "${existingByEndpoint.name}", updated heartbeat`);
            return;
        }
        const existing = registry.getAgentByName(peerName);
        if (existing) {
            // Update endpoint if changed
            if (existing.endpoint !== endpoint) {
                existing.endpoint = endpoint;
                existing.status = 'idle';
                existing.lastHeartbeat = Date.now();
                registry.upsertAgent(existing);
                registry.save();
                log.info(`mDNS: updated peer "${peerName}" endpoint to ${endpoint}`);
            }
        }
        else {
            registry.upsertAgent({
                id: peerId || `mdns-${Date.now()}`,
                name: peerName,
                type: 'remote',
                status: 'idle',
                capabilities: ['all'],
                endpoint,
                workspace: '',
                created: Date.now(),
                lastHeartbeat: Date.now(),
            });
            registry.save();
            log.info(`mDNS: registered new peer "${peerName}" at ${endpoint}`);
        }
    }
    catch (error) {
        log.debug('mDNS: error handling discovered service:', error);
    }
}
/**
 * Stop advertising and browsing. Call on shutdown.
 */
export function stopDiscovery() {
    try {
        if (publishedService) {
            publishedService.stop?.();
            publishedService = null;
        }
        if (browser) {
            browser.stop?.();
            browser = null;
        }
        if (bonjourInstance) {
            bonjourInstance.destroy?.();
            bonjourInstance = null;
        }
        log.debug('mDNS: discovery stopped');
    }
    catch (error) {
        log.debug('mDNS: error stopping discovery:', error);
    }
}
/**
 * Check if discovery is currently active.
 */
export function isDiscoveryActive() {
    return bonjourInstance !== null;
}
//# sourceMappingURL=peer-discovery.js.map