"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.activate = activate;
exports.deactivate = deactivate;
const vscode = __importStar(require("vscode"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const completions_1 = require("./language/completions");
const diagnostics_1 = require("./language/diagnostics");
const symbols_1 = require("./language/symbols");
const client_1 = require("./registry/client");
const engine_1 = require("./compiler/engine");
const nextest_1 = require("./nextest");
const modules_1 = require("./runtime/modules");
const NEXUS_LANGUAGE = "nexus";
const SELECTOR = { language: NEXUS_LANGUAGE };
let outputChannel;
let diagnostics;
function activate(context) {
    outputChannel = vscode.window.createOutputChannel("Nexus");
    context.subscriptions.push(outputChannel);
    diagnostics = new diagnostics_1.NexusDiagnostics();
    diagnostics.register(context);
    context.subscriptions.push({
        dispose: () => diagnostics?.dispose(),
    });
    context.subscriptions.push(vscode.languages.registerCompletionItemProvider(SELECTOR, new completions_1.NexusCompletionItemProvider()), vscode.languages.registerDocumentSymbolProvider(SELECTOR, new symbols_1.NexusDocumentSymbolProvider()));
    context.subscriptions.push(vscode.commands.registerCommand("nexus.run", () => runCommand(false)), vscode.commands.registerCommand("nexus.runVm", () => runCommand(true)), vscode.commands.registerCommand("nexus.selfhost", () => selfhostCommand()), vscode.commands.registerCommand("nexus.test", () => testCommand()), vscode.commands.registerCommand("nexus.repl", () => replCommand()), vscode.commands.registerCommand("nexus.compileWasm", () => compileCommand("wasm")), vscode.commands.registerCommand("nexus.compileLlvm", () => compileCommand("llvm")), vscode.commands.registerCommand("nexus.compileNative", () => compileCommand("native")), vscode.commands.registerCommand("nexus.publish", () => publishCommand()), vscode.commands.registerCommand("nexus.install", () => installCommand()));
    outputChannel.appendLine("Nexus TS toolchain ready: modules, bytecode VM, selfhost, tests, REPL, stdlib.");
}
function deactivate() {
    diagnostics?.dispose();
    diagnostics = undefined;
    outputChannel?.dispose();
    outputChannel = undefined;
}
function executionTier(forceVm) {
    if (forceVm) {
        return "vm";
    }
    const config = vscode.workspace.getConfiguration("nexus");
    const engine = config.get("executionEngine") ?? "eval";
    return engine === "vm" ? "vm" : "eval";
}
async function runCommand(forceVm = false) {
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
        void vscode.window.showErrorMessage("Nexus: no active editor to run.");
        return;
    }
    const document = editor.document;
    if (document.languageId !== NEXUS_LANGUAGE &&
        !document.fileName.endsWith(".nex")) {
        const proceed = await vscode.window.showWarningMessage("The active file does not appear to be a Nexus (.nex) file. Run anyway?", "Run", "Cancel");
        if (proceed !== "Run") {
            return;
        }
    }
    const source = document.getText();
    const channel = ensureOutput();
    channel.clear();
    channel.show(true);
    const tier = executionTier(forceVm);
    channel.appendLine(`Running ${document.fileName || "untitled"} [${tier}]…`);
    channel.appendLine("─".repeat(40));
    const workspaceRoot = getWorkspaceRoot() ?? path.dirname(document.fileName || process.cwd());
    try {
        const result = await (0, engine_1.evaluate)(source, {
            tier,
            rootDir: workspaceRoot,
            modulesDir: path.join(workspaceRoot, modules_1.MODULES_DIRNAME),
            stdlibDir: (0, modules_1.findStdlibDir)(workspaceRoot),
            filePath: document.fileName || undefined,
            checkOwnership: false,
            enableEffects: false,
        });
        for (const d of result.diagnostics) {
            if (d.phase === "ownership" ||
                d.phase === "parse" ||
                d.phase === "effects" ||
                d.phase === "vm") {
                channel.appendLine(`[${d.phase}] ${d.message}`);
            }
        }
        for (const line of result.output) {
            channel.appendLine(line);
        }
        if (result.value.type === "ERROR") {
            channel.appendLine(result.value.inspect());
            void vscode.window.showErrorMessage(`Nexus runtime error: ${result.value.inspect()}`);
            return;
        }
        if (result.value.type !== "NULL") {
            channel.appendLine(result.value.inspect());
        }
        channel.appendLine("─".repeat(40));
        channel.appendLine("Finished.");
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        channel.appendLine(`Fatal error: ${message}`);
        void vscode.window.showErrorMessage(`Nexus: ${message}`);
    }
}
async function selfhostCommand() {
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
        void vscode.window.showErrorMessage("Nexus: no active editor to selfhost.");
        return;
    }
    const document = editor.document;
    if (!document.fileName.endsWith(".nex")) {
        void vscode.window.showErrorMessage("Nexus selfhost: save a .nex file first.");
        return;
    }
    await document.save();
    const workspaceRoot = getWorkspaceRoot() ?? path.dirname(document.fileName);
    const channel = ensureOutput();
    channel.clear();
    channel.show(true);
    channel.appendLine(`Selfhosting ${document.fileName}…`);
    channel.appendLine("─".repeat(40));
    const candidates = [
        path.join(workspaceRoot, "vscode-nexus", "out", "cli.js"),
        path.join(workspaceRoot, "out", "cli.js"),
        path.join(__dirname, "cli.js"),
    ];
    const cli = candidates.find((c) => fs.existsSync(c));
    if (!cli) {
        void vscode.window.showErrorMessage("Nexus selfhost: could not find out/cli.js (run npm run compile).");
        return;
    }
    const { spawn } = await Promise.resolve().then(() => __importStar(require("child_process")));
    const cliRoot = path.dirname(path.dirname(cli));
    await new Promise((resolve) => {
        const child = spawn(process.execPath, [cli, "selfhost", document.fileName], { cwd: cliRoot });
        child.stdout.on("data", (buf) => {
            channel.append(buf.toString());
        });
        child.stderr.on("data", (buf) => {
            channel.append(buf.toString());
        });
        child.on("close", (code) => {
            channel.appendLine("─".repeat(40));
            channel.appendLine(code === 0 ? "Selfhost finished." : `Selfhost exited ${code}`);
            resolve();
        });
    });
}
async function testCommand() {
    const workspaceRoot = getWorkspaceRoot();
    if (!workspaceRoot) {
        void vscode.window.showErrorMessage("Nexus: open a workspace folder before running tests.");
        return;
    }
    const channel = ensureOutput();
    channel.clear();
    channel.show(true);
    channel.appendLine(`Running Nexus tests in ${workspaceRoot}…`);
    channel.appendLine("─".repeat(40));
    try {
        const summary = await (0, nextest_1.runTests)({
            rootDir: workspaceRoot,
            stdlibDir: (0, modules_1.findStdlibDir)(workspaceRoot),
            out: (line) => channel.appendLine(line),
        });
        if (summary.failed > 0) {
            void vscode.window.showErrorMessage(`Nexus tests: ${summary.failed} failed, ${summary.passed} passed`);
        }
        else {
            void vscode.window.showInformationMessage(`Nexus tests: ${summary.passed} passed`);
        }
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        channel.appendLine(message);
        void vscode.window.showErrorMessage(`Nexus test: ${message}`);
    }
}
async function replCommand() {
    const workspaceRoot = getWorkspaceRoot() ?? process.cwd();
    const config = vscode.workspace.getConfiguration("nexus");
    const engine = config.get("executionEngine") === "vm" ? "vm" : "eval";
    const terminal = vscode.window.createTerminal({
        name: "Nexus REPL",
        cwd: workspaceRoot,
    });
    terminal.show();
    // Prefer compiled CLI under the extension install / workspace vscode-nexus
    const candidates = [
        path.join(workspaceRoot, "vscode-nexus", "out", "cli.js"),
        path.join(workspaceRoot, "out", "cli.js"),
        path.join(__dirname, "cli.js"),
    ];
    const cli = candidates.find((c) => fs.existsSync(c));
    if (!cli) {
        void vscode.window.showErrorMessage("Nexus REPL: could not find out/cli.js (run npm run compile in vscode-nexus).");
        return;
    }
    const vmFlag = engine === "vm" ? " --vm" : "";
    terminal.sendText(`node "${cli}" repl${vmFlag}`);
}
async function compileCommand(target) {
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
        void vscode.window.showErrorMessage("Nexus: no active editor to compile.");
        return;
    }
    const document = editor.document;
    const source = document.getText();
    const channel = ensureOutput();
    channel.show(true);
    const config = vscode.workspace.getConfiguration("nexus");
    const configuredOut = config.get("compileOutputDir");
    const workspaceRoot = getWorkspaceRoot();
    const outputDir = configuredOut ||
        (workspaceRoot
            ? path.join(workspaceRoot, "nex-out")
            : path.join(path.dirname(document.fileName || process.cwd()), "nex-out"));
    const base = path.basename(document.fileName || "main.nex", path.extname(document.fileName || "main.nex"));
    channel.appendLine(`Compiling → ${target} into ${outputDir}…`);
    try {
        const artifact = target === "wasm"
            ? (0, engine_1.compileToWasm)(source, outputDir)
            : target === "llvm"
                ? (0, engine_1.compileToLlvm)(source, outputDir)
                : (0, engine_1.compileToNative)(source, outputDir);
        for (const d of artifact.diagnostics) {
            channel.appendLine(`[${d.phase}] ${d.message}`);
        }
        if (artifact.codegen) {
            for (const w of artifact.codegen.warnings) {
                channel.appendLine(`[codegen] ${w}`);
            }
        }
        if (artifact.codegen && !artifact.outputPath) {
            const { writeFileSync, mkdirSync } = await Promise.resolve().then(() => __importStar(require("fs")));
            mkdirSync(outputDir, { recursive: true });
            const ext = target === "llvm" ? "ll" : "wat";
            const outPath = path.join(outputDir, `${base}.${ext}`);
            writeFileSync(outPath, artifact.codegen.source, "utf8");
            channel.appendLine(`Wrote ${outPath}`);
        }
        else if (artifact.outputPath) {
            channel.appendLine(`Wrote ${artifact.outputPath}`);
        }
        void vscode.window.showInformationMessage(`Nexus: compiled ${target} → ${artifact.outputPath ?? outputDir}`);
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        channel.appendLine(`Compile failed: ${message}`);
        void vscode.window.showErrorMessage(`Nexus compile failed: ${message}`);
    }
}
async function publishCommand() {
    const workspaceRoot = getWorkspaceRoot();
    if (!workspaceRoot) {
        void vscode.window.showErrorMessage("Nexus: open a workspace folder before publishing.");
        return;
    }
    const channel = ensureOutput();
    channel.show(true);
    channel.appendLine(`Publishing workspace: ${workspaceRoot}`);
    try {
        const client = createClient();
        channel.appendLine(`Registry: ${client.baseUrl}`);
        await vscode.window.withProgress({
            location: vscode.ProgressLocation.Notification,
            title: "Nexus: publishing package…",
            cancellable: false,
        }, async () => {
            const result = await client.publish(workspaceRoot);
            const msg = result.message ||
                `Published ${result.package.name}@${result.package.version}`;
            channel.appendLine(msg);
            channel.appendLine(`Checksum: ${result.package.checksum}`);
            void vscode.window.showInformationMessage(`Nexus: ${msg}`);
        });
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        channel.appendLine(`Publish failed: ${message}`);
        void vscode.window.showErrorMessage(`Nexus publish failed: ${message}`);
    }
}
async function installCommand() {
    const workspaceRoot = getWorkspaceRoot();
    if (!workspaceRoot) {
        void vscode.window.showErrorMessage("Nexus: open a workspace folder before installing packages.");
        return;
    }
    const spec = await vscode.window.showInputBox({
        title: "Nexus: Install Package",
        prompt: "Package name (optional @version)",
        placeHolder: "leftpad@1.0.0",
        ignoreFocusOut: true,
        validateInput: (value) => value.trim().length === 0 ? "Package name is required" : undefined,
    });
    if (!spec) {
        return;
    }
    const channel = ensureOutput();
    channel.show(true);
    channel.appendLine(`Installing ${spec.trim()}…`);
    try {
        const client = createClient();
        await vscode.window.withProgress({
            location: vscode.ProgressLocation.Notification,
            title: `Nexus: installing ${spec.trim()}…`,
            cancellable: false,
        }, async () => {
            const result = await client.install(workspaceRoot, spec.trim());
            const msg = `Installed ${result.name}@${result.version} → ${result.destination}`;
            channel.appendLine(msg);
            void vscode.window.showInformationMessage(`Nexus: ${msg}`);
        });
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        channel.appendLine(`Install failed: ${message}`);
        void vscode.window.showErrorMessage(`Nexus install failed: ${message}`);
    }
}
function createClient() {
    const config = vscode.workspace.getConfiguration("nexus");
    const registryUrl = config.get("registryUrl") ||
        process.env.NEX_REGISTRY_URL ||
        client_1.DEFAULT_REGISTRY_URL;
    return new client_1.RegistryClient({ registryUrl });
}
function getWorkspaceRoot() {
    const folders = vscode.workspace.workspaceFolders;
    if (!folders || folders.length === 0) {
        return undefined;
    }
    const editor = vscode.window.activeTextEditor;
    if (editor?.document.uri.scheme === "file") {
        const folder = vscode.workspace.getWorkspaceFolder(editor.document.uri);
        if (folder) {
            return folder.uri.fsPath;
        }
    }
    return folders[0]?.uri.fsPath;
}
function ensureOutput() {
    if (!outputChannel) {
        outputChannel = vscode.window.createOutputChannel("Nexus");
    }
    return outputChannel;
}
//# sourceMappingURL=extension.js.map