// tools/lsp/vscode-extension/extension.js
//
// El Language VSCode extension — Language Client
//
// Launches the el-lsp binary as a child process and connects VSCode's
// Language Client to it over stdin/stdout (JSON-RPC 2.0 + Content-Length).
//
// Capabilities provided by el-lsp:
//   - textDocumentSync (full)
//   - completionProvider  — builtins + user fns + keywords
//   - hoverProvider       — signatures + descriptions
//   - definitionProvider  — go-to-def for user-defined fns
//   - diagnostics         — unclosed braces/parens, unterminated strings
//
// Setup (development):
//   1. cd tools/lsp && ./build.sh          (builds dist/el-lsp)
//   2. cd vscode-extension && npm install  (installs vscode-languageclient)
//   3. Open vscode-extension/ in VSCode
//   4. Press F5                            (launches Extension Development Host)
//   5. Open any .el file
//
// Package as .vsix:
//   npm install -g @vscode/vsce
//   cd tools/lsp/vscode-extension && vsce package

'use strict';

const path = require('path');
const fs   = require('fs');
const { workspace, window, ExtensionContext } = require('vscode');
const {
    LanguageClient,
    TransportKind,
} = require('vscode-languageclient/node');

/** @type {LanguageClient | undefined} */
let client;

/**
 * activate — entry point called when any .el file is first opened.
 *
 * @param {ExtensionContext} context
 */
function activate(context) {
    // ── Resolve el-lsp binary ────────────────────────────────────────────
    const config = workspace.getConfiguration('el');

    // Default path resolution (tries in order):
    //   1. el.lspPath setting (user override)
    //   2. dist/el-lsp alongside the extension dir (packaged install)
    //   3. The canonical source-tree location
    const CANONICAL_LSP = '/Users/will/Development/neuron-technologies/foundation/el/tools/lsp/dist/el-lsp';
    const defaultLspPath = (() => {
        const sibling = path.join(context.extensionPath, 'dist', 'el-lsp');
        if (fs.existsSync(sibling)) return sibling;
        return CANONICAL_LSP;
    })();
    const serverPath = config.get('lspPath') || defaultLspPath;

    if (!fs.existsSync(serverPath)) {
        window.showErrorMessage(
            `El Language Server binary not found at: ${serverPath}\n` +
            `Run tools/lsp/build.sh to build it, then reload VSCode.\n` +
            `Or set "el.lspPath" in settings to the correct path.`
        );
        return;
    }

    // ── Server options (start el-lsp as child process) ───────────────────
    /** @type {import('vscode-languageclient/node').ServerOptions} */
    const serverOptions = {
        run: {
            command:   serverPath,
            transport: TransportKind.stdio,
            options:   { env: { ...process.env } },
        },
        debug: {
            command:   serverPath,
            transport: TransportKind.stdio,
            options: {
                env: { ...process.env },
                // Redirect el-lsp stderr to VSCode's Output panel in debug mode.
            },
        },
    };

    // ── Client options ───────────────────────────────────────────────────
    /** @type {import('vscode-languageclient/node').LanguageClientOptions} */
    const clientOptions = {
        // Activate for all .el files (file:// and untitled: schemes).
        documentSelector: [
            { scheme: 'file',     language: 'el' },
            { scheme: 'untitled', language: 'el' },
        ],
        synchronize: {
            // Fire fileEvents so the client resends on disk changes outside VSCode.
            fileEvents: workspace.createFileSystemWatcher('**/*.el'),
        },
        outputChannelName: 'El Language Server',
        // Trace LSP messages to the Output panel for debugging.
        // Set "el.trace.server": "verbose" in settings to enable.
        traceOutputChannel: window.createOutputChannel('El LSP Trace'),
    };

    // ── Create and start client ──────────────────────────────────────────
    client = new LanguageClient(
        'el-language-server',
        'El Language Server',
        serverOptions,
        clientOptions,
    );

    // Register the client so it is disposed when the extension deactivates.
    context.subscriptions.push(client);

    client.start().then(() => {
        // Show a discrete status bar item while the server is active.
        const status = window.createStatusBarItem(1);
        status.text    = '$(symbol-misc) El LSP';
        status.tooltip = 'El Language Server is running';
        status.command = 'el.restartServer';
        status.show();
        context.subscriptions.push(status);
    }).catch((err) => {
        window.showErrorMessage(`El Language Server failed to start: ${err.message}`);
    });

    // ── Commands ─────────────────────────────────────────────────────────
    context.subscriptions.push(
        require('vscode').commands.registerCommand('el.restartServer', () => {
            if (client) {
                client.stop().then(() => client.start());
                window.showInformationMessage('El Language Server restarted.');
            }
        })
    );
}

/**
 * deactivate — called when the extension is unloaded.
 * Sends LSP shutdown + exit to the server process.
 */
function deactivate() {
    if (!client) {
        return undefined;
    }
    return client.stop();
}

module.exports = { activate, deactivate };
