"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VersionConflictError = void 0;
exports.noopContext = noopContext;
exports.resolveExternalGraph = resolveExternalGraph;
exports.findIncomingCrossLinks = findIncomingCrossLinks;
/** Thrown when an update specifies an expectedVersion that doesn't match the current node version. */
class VersionConflictError extends Error {
    current;
    expected;
    constructor(current, expected) {
        super(`Version conflict: expected ${expected}, current is ${current}`);
        this.current = current;
        this.expected = expected;
        this.name = 'VersionConflictError';
    }
}
exports.VersionConflictError = VersionConflictError;
/** No-op context for tests. */
function noopContext(projectId = '') {
    return {
        markDirty: () => { },
        emit: () => { },
        projectId,
        author: '',
    };
}
/**
 * Resolve a targetGraph string to the actual graph instance.
 * When projectId is given (workspace mode), per-project graphs are checked first.
 */
function resolveExternalGraph(ext, targetGraph, projectId) {
    // In workspace mode, resolve per-project indexed graphs first
    if (projectId && ext.projectGraphs) {
        const pg = ext.projectGraphs.get(projectId);
        if (pg) {
            switch (targetGraph) {
                case 'docs': return pg.docGraph;
                case 'code': return pg.codeGraph;
                case 'files': return pg.fileIndexGraph;
            }
        }
    }
    switch (targetGraph) {
        case 'docs': return ext.docGraph;
        case 'code': return ext.codeGraph;
        case 'files': return ext.fileIndexGraph;
        case 'knowledge': return ext.knowledgeGraph;
        case 'tasks': return ext.taskGraph;
        case 'skills': return ext.skillGraph;
        default: return undefined;
    }
}
/**
 * Find all cross-graph links that point to `nodeId` in `graphName`
 * by scanning proxy nodes in Knowledge, Task, and Skill graphs.
 * Checks both legacy (`@graph::nodeId`) and project-scoped (`@graph::projectId::nodeId`) proxies.
 */
function findIncomingCrossLinks(ext, graphName, nodeId, projectId) {
    const results = [];
    // Candidate proxy IDs: legacy format + project-scoped format
    const candidates = [`@${graphName}::${nodeId}`];
    if (projectId)
        candidates.push(`@${graphName}::${projectId}::${nodeId}`);
    function scanGraph(graph, sourceGraphName) {
        if (!graph)
            return;
        for (const pId of candidates) {
            if (!graph.hasNode(pId))
                continue;
            graph.forEachInEdge(pId, (_edge, attrs, source) => {
                const sourceAttrs = graph.getNodeAttributes(source);
                if (sourceAttrs.proxyFor)
                    return; // skip proxy-to-proxy
                results.push({
                    sourceId: source,
                    sourceGraph: sourceGraphName,
                    kind: attrs.kind,
                });
            });
        }
    }
    scanGraph(ext.knowledgeGraph, 'knowledge');
    scanGraph(ext.taskGraph, 'tasks');
    scanGraph(ext.skillGraph, 'skills');
    return results;
}
