import { findDefinition, getWordAtPosition } from "../cli/definition.js";
import { pathToUri } from "./uri.js";
import { lookupSemanticSymbol } from "./semantics.js";
import { findContainingScope, findDefForScope } from "./scopeResolution.js";
import { walkNodes } from "../utils/node.js";
import { offsetOfLine } from "./util.js";
export function handleDefinition(params, doc, fsPath, semanticIndex, program, scopes) {
    const source = doc.getText();
    const symbol = lookupSemanticSymbol(source, params.position.line, params.position.character, semanticIndex);
    if (symbol?.loc) {
        return {
            uri: pathToUri(symbol.filePath),
            range: {
                start: { line: symbol.loc.line, character: symbol.loc.col },
                end: { line: symbol.loc.line, character: symbol.loc.col },
            },
        };
    }
    // Try local variable definition via AST
    if (program && scopes) {
        const loc = findLocalDefinition(source, params.position.line, params.position.character, program, scopes);
        if (loc) {
            return { uri: doc.uri, range: { start: loc, end: loc } };
        }
    }
    const result = findDefinition(source, params.position.line, params.position.character, fsPath);
    if (!result)
        return null;
    return {
        uri: pathToUri(result.file),
        range: {
            start: { line: result.line, character: result.column },
            end: { line: result.line, character: result.column },
        },
    };
}
function findLocalDefinition(source, line, character, program, scopes) {
    const word = getWordAtPosition(source, line, character);
    if (!word)
        return null;
    const offset = offsetOfLine(source, line) + character;
    const scope = findContainingScope(offset, scopes, program);
    if (!scope)
        return null;
    if (!scope.scope.lookup(word))
        return null;
    for (const { node } of walkNodes(scope.body)) {
        if (node.type === "assignment" && node.variableName === word && node.declKind && node.loc) {
            return { line: node.loc.line, character: node.loc.col };
        }
    }
    // Jump to containing function/node header for parameters
    const def = findDefForScope(scope.name, program);
    if (def && "parameters" in def) {
        const param = def.parameters.find((p) => p.name === word);
        if (param && def.loc) {
            return { line: def.loc.line, character: def.loc.col };
        }
    }
    return null;
}
