/**
 * Bare-Metal Companion Services Launcher
 *
 * Starts the license server and dashboard as background child processes
 * when running in bare-metal mode (no Docker container).
 *
 * These services are optional — the MCP stdio server works without them.
 * If they fail to start, a warning is logged but the MCP server continues.
 *
 * @module bare-metal-services
 */
import { spawn } from 'child_process';
import { existsSync } from 'fs';
import { join, dirname } from 'path';
import { homedir } from 'os';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const BARE_METAL_DIR = join(homedir(), '.ocr-provenance-mcp');
const DASHBOARD_DIR = join(BARE_METAL_DIR, 'dashboard');
// License server path — check npm package location first, then source repo fallback
const LICENSE_SERVER_DIRS = [
    join(__dirname, '..', 'packages', 'server', 'dist'), // npm package: <pkg>/packages/server/dist/
    join(__dirname, '..', '..', 'packages', 'server', 'dist'), // source repo fallback
];
const activeProcesses = [];
function log(msg) {
    process.stderr.write(`[bare-metal] ${msg}\n`);
}
/**
 * Start companion services for bare-metal mode.
 * Non-blocking — services start in the background.
 * Failures are logged but do not prevent MCP server startup.
 */
export function startBareMetalServices() {
    // Clean up child processes on exit
    const cleanup = () => {
        for (const proc of activeProcesses) {
            try {
                proc.kill();
            }
            catch { /* already dead */ }
        }
    };
    process.on('exit', cleanup);
    process.on('SIGTERM', () => { cleanup(); process.exit(0); });
    process.on('SIGINT', () => { cleanup(); process.exit(0); });
    startLicenseServer();
    startDashboard();
}
function startLicenseServer() {
    // Find the license server binary. Check multiple locations because the path
    // differs between npm install (node_modules/ocr-provenance-mcp/packages/server/dist/)
    // and source repo (../../packages/server/dist/).
    let entry = null;
    for (const dir of LICENSE_SERVER_DIRS) {
        const candidate = join(dir, 'index.js');
        if (existsSync(candidate)) {
            entry = candidate;
            break;
        }
    }
    if (!entry) {
        log('License server not found — billing features unavailable.');
        log('  OCR processing works without billing. To add funds, use Docker mode.');
        return;
    }
    const port = process.env.LICENSE_PORT ?? '3000';
    log(`Starting license server on port ${port}...`);
    const proc = spawn('node', [entry], {
        env: {
            ...process.env,
            LICENSE_PORT: port,
            PORT: undefined, // Don't let PORT leak to license server
        },
        stdio: ['pipe', 'pipe', 'pipe'],
        detached: false,
    });
    activeProcesses.push(proc);
    proc.stderr?.on('data', (chunk) => {
        for (const line of chunk.toString().split('\n')) {
            if (line.trim())
                process.stderr.write(`[license] ${line}\n`);
        }
    });
    proc.on('exit', (code) => {
        if (code !== 0 && code !== null) {
            log(`License server exited with code ${code}`);
        }
    });
}
function startDashboard() {
    // Check installed location first, then bundled fallback in npm package
    let dashboardDir = DASHBOARD_DIR;
    let dashboardServer = join(DASHBOARD_DIR, 'server.js');
    if (!existsSync(dashboardServer)) {
        // Fallback: check bundled dashboard in npm package
        const bundled = join(__dirname, '..', 'packages', 'wrapper', 'dashboard-bundle', 'server.js');
        if (existsSync(bundled)) {
            dashboardDir = join(__dirname, '..', 'packages', 'wrapper', 'dashboard-bundle');
            dashboardServer = bundled;
        }
        else {
            log('Dashboard not installed — web UI unavailable.');
            log('  Re-run: npx -y ocr-provenance-mcp install --mac');
            return;
        }
    }
    const port = process.env.DASHBOARD_PORT ?? process.env.PORT ?? '3367';
    const licensePort = process.env.LICENSE_PORT ?? '3000';
    const mcpPort = process.env.MCP_HTTP_PORT ?? '3366';
    log(`Starting dashboard on port ${port}...`);
    const proc = spawn('node', [dashboardServer], {
        cwd: dashboardDir,
        env: {
            PATH: process.env.PATH,
            HOME: dashboardDir,
            NODE_ENV: 'production',
            PORT: port,
            HOSTNAME: '127.0.0.1',
            SESSION_SECRET: process.env.SESSION_SECRET ?? 'bare-metal-dev-session-secret',
            OCR_LICENSE_KEY: process.env.OCR_LICENSE_KEY ?? '',
            OCR_LICENSE_SERVER: `http://127.0.0.1:${licensePort}`,
            MCP_SERVER_URL: `http://127.0.0.1:${mcpPort}`,
            DASHBOARD_URL: `http://127.0.0.1:${port}`,
        },
        stdio: ['pipe', 'pipe', 'pipe'],
        detached: false,
    });
    activeProcesses.push(proc);
    proc.stderr?.on('data', (chunk) => {
        for (const line of chunk.toString().split('\n')) {
            if (line.trim())
                process.stderr.write(`[dashboard] ${line}\n`);
        }
    });
    proc.stdout?.on('data', (chunk) => {
        const text = chunk.toString();
        if (text.includes('Ready')) {
            log(`Dashboard ready at http://localhost:${port}`);
        }
    });
    proc.on('exit', (code) => {
        if (code !== 0 && code !== null) {
            log(`Dashboard exited with code ${code}`);
        }
    });
}
//# sourceMappingURL=bare-metal-services.js.map