import { findNodeAtOffset, getIdentifierText } from "../checker.js";
import { isIdentifierNode } from "../parser.js";
import { SyntaxKind, } from "../types.js";
import { getEdgeStr } from "./command/common.js";
import { syntaxNodeToRange } from "./util.js";
export function hover(doc, sourceFile, position) {
    const offset = doc.offsetAt(position);
    const g = sourceFile.graph;
    if (!g)
        return undefined;
    const node = findNodeAtOffset(g, offset);
    if (node === undefined)
        return undefined;
    return getNodeHover(doc, sourceFile, node);
}
function getNodeHover(doc, sf, n) {
    const contents = getHoverContents(n);
    if (contents) {
        return {
            contents,
            range: syntaxNodeToRange(doc, sf, n),
        };
    }
    return undefined;
}
function getAssignedLabel(statement) {
    const assignments = statement.attributes.flatMap(a => a.assignments);
    const assignedLabel = assignments?.find(a => getIdentifierText(a.leftId) === "label");
    return assignedLabel?.rightId ? getIdentifierText(assignedLabel.rightId) : undefined;
}
function getHoverContents(n) {
    if (isIdentifierNode(n)) {
        const parent = n.parent;
        if (parent) {
            switch (parent.kind) {
                case SyntaxKind.NodeId: {
                    if (n.symbol?.references) {
                        const nodeIdentifierRefs = n.symbol?.references;
                        const labelMentions = nodeIdentifierRefs.map(e => e.symbol?.members?.get("label")?.firstMention.parent);
                        for (let i = labelMentions.length; i >= 0; i--) {
                            const s = labelMentions[i];
                            if (s?.rightId) {
                                return `(node) ${getIdentifierText(n)}: ${getIdentifierText(s.rightId)}`;
                            }
                        }
                    }
                    else if (parent.parent?.kind === SyntaxKind.NodeStatement) {
                        const label = getAssignedLabel(parent.parent);
                        if (label) {
                            return `(node) ${getIdentifierText(n)}: ${label}`;
                        }
                    }
                    return `(node) ${getIdentifierText(n)}`;
                }
                case SyntaxKind.Assignment: {
                    const assignment = parent;
                    const left = getIdentifierText(assignment.leftId);
                    const right = getIdentifierText(assignment.rightId);
                    return `(assignment) \`${left}\` = \`${right}\``;
                }
                case SyntaxKind.DirectedGraph:
                    return getGraphHover(parent);
                case SyntaxKind.UndirectedGraph:
                    return getGraphHover(parent);
                case SyntaxKind.SubGraphStatement: {
                    const sgs = parent;
                    const sg = sgs.subgraph;
                    return sg.id ? `(sub graph) ${getIdentifierText(sg.id)}` : "(sub graph)";
                }
                case SyntaxKind.SubGraph: {
                    const sg = parent;
                    return sg.id ? `(sub graph) ${getIdentifierText(sg.id)}` : "(sub graph)";
                }
                case SyntaxKind.IdEqualsIdStatement: {
                    const idEqId = parent;
                    const left = getIdentifierText(idEqId.leftId);
                    const right = getIdentifierText(idEqId.rightId);
                    return `(graph property) \`${left}\` = \`${right}\``;
                }
                case SyntaxKind.EdgeRhs:
                    return getEdgeHover(parent);
            }
            return SyntaxKind[parent.kind];
        }
        const fallback = SyntaxKind[n.kind];
        return fallback ? `(${fallback.toLowerCase()})` : undefined;
    }
    switch (n.kind) {
        case SyntaxKind.GraphKeyword:
        case SyntaxKind.DigraphKeyword:
        case SyntaxKind.StrictKeyword:
            return getGraphHover(n.parent);
        case SyntaxKind.DirectedGraph:
        case SyntaxKind.UndirectedGraph:
            return getGraphHover(n);
        case SyntaxKind.DirectedEdgeOp:
        case SyntaxKind.UndirectedEdgeOp:
            return getEdgeHover(n.parent);
        default:
            return undefined;
    }
}
function getGraphHover(g) {
    const direction = g.kind === SyntaxKind.DirectedGraph ? "directed" : "undirected";
    const graphId = g.id;
    const strict = g.strict ? "strict " : "";
    return graphId
        ? `(${strict}${direction} graph) ${getIdentifierText(graphId)}`
        : `(${strict}${direction} graph)`;
}
function getEdgeHover(n) {
    const p = n.parent;
    if (!p || p.rhs.length === 0)
        return undefined;
    let source = undefined;
    for (const curr of p.rhs) {
        if (curr === n)
            break;
        source = curr.target;
    }
    if (source === undefined)
        source = p.source;
    const edgeOpStr = getEdgeStr(n.operation.kind);
    return source === undefined
        ? undefined
        : `(edge) ${getEdgeSourceOrTargetText(source)} ${edgeOpStr} ${getEdgeSourceOrTargetText(n.target)}`;
}
function getEdgeSourceOrTargetText(n) {
    return n.kind === SyntaxKind.NodeId
        ? getIdentifierText(n.id)
        : n.id !== undefined
            ? `${getIdentifierText(n.id)}`
            : "sub graph";
}
//# sourceMappingURL=hover.js.map