import { existsSync, readFileSync } from "fs";
import { resolve } from "path";
import { LSPClient } from "./client.js";
import { findServerForFile, getLanguageId, isServerAvailable } from "./server-registry.js";
export class LSPService {
    servers = new Map();
    async ensureServer(filePath) {
        const absPath = resolve(filePath);
        // Check if we already have a server for this path
        for (const [, server] of this.servers) {
            if (absPath.startsWith(server.rootPath)) {
                return server.client;
            }
        }
        const match = findServerForFile(absPath);
        if (!match)
            return null;
        if (!isServerAvailable(match.info))
            return null;
        // Check if already running for this root
        for (const [, server] of this.servers) {
            if (server.rootPath === match.rootPath) {
                return server.client;
            }
        }
        try {
            const client = new LSPClient({
                command: match.info.command,
                args: match.info.args,
                cwd: match.rootPath,
                rootUri: `file://${match.rootPath}`,
            });
            await client.start();
            this.servers.set(match.info.id, { client, rootPath: match.rootPath });
            return client;
        }
        catch {
            return null;
        }
    }
    async openFile(filePath) {
        const client = await this.ensureServer(filePath);
        if (!client)
            return null;
        const absPath = resolve(filePath);
        if (!existsSync(absPath))
            return client;
        const ext = Object.keys({
            ".ts": 1,
            ".tsx": 1,
            ".js": 1,
            ".jsx": 1,
            ".mjs": 1,
            ".cjs": 1,
            ".mts": 1,
            ".cts": 1,
            ".py": 1,
            ".go": 1,
            ".rs": 1,
            ".c": 1,
            ".cpp": 1,
            ".h": 1,
            ".hpp": 1,
            ".rb": 1,
            ".ex": 1,
            ".exs": 1,
            ".zig": 1,
            ".sh": 1,
            ".bash": 1,
        }).find((e) => absPath.endsWith(e));
        if (!ext)
            return client;
        const langId = getLanguageId(ext) ?? "plaintext";
        const text = readFileSync(absPath, "utf-8");
        await client.openDocument(`file://${absPath}`, langId, text);
        return client;
    }
    async hover(filePath, line, column) {
        const client = await this.openFile(filePath);
        if (!client)
            return null;
        const result = (await client.hover(`file://${resolve(filePath)}`, line, column));
        if (!result)
            return null;
        const contents = result.contents;
        if (typeof contents === "string")
            return { contents };
        if (Array.isArray(contents)) {
            return {
                contents: contents
                    .map((c) => (typeof c === "string" ? c : (c?.value ?? "")))
                    .join("\n"),
            };
        }
        if (contents && typeof contents === "object") {
            const c = contents;
            return { contents: c.value ?? JSON.stringify(c) };
        }
        return null;
    }
    async definition(filePath, line, column) {
        const client = await this.openFile(filePath);
        if (!client)
            return null;
        const result = await client.definition(`file://${resolve(filePath)}`, line, column);
        if (!result)
            return null;
        if (Array.isArray(result)) {
            return result.map((loc) => {
                const uri = loc.uri;
                const start = loc.range?.start ?? {
                    line: 0,
                    character: 0,
                };
                return { uri, line: start.line ?? 0, column: start.character ?? 0 };
            });
        }
        const loc = result;
        const start = loc.range?.start ?? {
            line: 0,
            character: 0,
        };
        return [
            { uri: loc.targetUri ?? loc.uri, line: start.line ?? 0, column: start.character ?? 0 },
        ];
    }
    async references(filePath, line, column) {
        const client = await this.openFile(filePath);
        if (!client)
            return null;
        const result = await client.references(`file://${resolve(filePath)}`, line, column);
        if (!Array.isArray(result))
            return null;
        return result.map((loc) => {
            const start = loc.range?.start ?? {
                line: 0,
                character: 0,
            };
            return { uri: loc.uri, line: start.line ?? 0, column: start.character ?? 0 };
        });
    }
    async documentSymbols(filePath) {
        const client = await this.openFile(filePath);
        if (!client)
            return null;
        const result = await client.documentSymbols(`file://${resolve(filePath)}`);
        if (!Array.isArray(result))
            return null;
        return result.map((sym) => {
            const start = (sym.range ?? sym.selectionRange);
            const pos = (start?.start ?? start) ?? { line: 0 };
            return { name: sym.name ?? "", kind: sym.kind ?? 0, line: pos.line ?? 0 };
        });
    }
    shutdownAll() {
        for (const [, server] of this.servers) {
            server.client.shutdown().catch(() => { });
        }
        this.servers.clear();
    }
}
const globalService = new LSPService();
export function getLSPService() {
    return globalService;
}
export function shutdownLSPServers() {
    globalService.shutdownAll();
}
//# sourceMappingURL=index.js.map