"use strict";
// src/cli/GraphCommand.ts
// v1.14.0 — `openlife graph {build,callers,deps,usages,find,status}`.
// v1.14.1 — path normalization (abs / cwd-relative / bare basename),
// file:line refs in deps output, (npm)/(project) qualifiers.
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.registerGraphCommands = registerGraphCommands;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
/**
 * Resolve a user-typed file argument to the absolute path stored in the
 * graph DB. Tries: absolute → cwd-relative → suffix match in DB. Returns
 * { matches } where matches is 0/1/many. Caller renders disambiguation
 * when many.
 */
async function resolveFileArg(input) {
    const candidates = [];
    // 1. Absolute path (already canonical)
    if (path.isAbsolute(input)) {
        try {
            if (fs.statSync(input).isFile())
                candidates.push(input);
        }
        catch { /* not on disk — fall through */ }
    }
    else {
        // 2. cwd-relative
        const cwdRel = path.resolve(process.cwd(), input);
        try {
            if (fs.statSync(cwdRel).isFile())
                candidates.push(cwdRel);
        }
        catch { /* */ }
    }
    // Always also try suffix match in the DB — covers bare basename, partial
    // path, or paths that point at a different machine's filesystem.
    const { GraphStore } = await Promise.resolve().then(() => __importStar(require('../orchestrator/graph/GraphStore')));
    const store = new GraphStore();
    try {
        const dbMatches = store.findFilesBySuffix(input);
        for (const m of dbMatches) {
            if (!candidates.includes(m))
                candidates.push(m);
        }
    }
    finally {
        store.close();
    }
    return { matches: candidates };
}
async function withStore(fn) {
    const { GraphStore } = await Promise.resolve().then(() => __importStar(require('../orchestrator/graph/GraphStore')));
    const store = new GraphStore();
    try {
        return await fn(store);
    }
    finally {
        store.close();
    }
}
async function buildCmd(opts) {
    const { GraphStore } = await Promise.resolve().then(() => __importStar(require('../orchestrator/graph/GraphStore')));
    const { GraphBuilder } = await Promise.resolve().then(() => __importStar(require('../orchestrator/graph/GraphBuilder')));
    const store = new GraphStore();
    const builder = new GraphBuilder();
    const root = opts.root || process.cwd();
    console.log(`[GRAPH] build from ${root}`);
    let lastLog = '';
    const report = builder.build(root, store, (file, done, total) => {
        if (done % 50 === 0 || done === total) {
            const line = `[GRAPH] ${done}/${total} ${file}`;
            if (line !== lastLog) {
                console.log(line);
                lastLog = line;
            }
        }
    });
    store.close();
    console.log(`[GRAPH] done: scanned=${report.scannedFiles} symbols=${report.symbols} edges=${report.edges} failures=${report.failedFiles.length}`);
}
async function statusCmd() {
    await withStore((store) => {
        const { symbols, edges } = store.size();
        console.log(`symbols: ${symbols}\nedges: ${edges}`);
    });
}
async function findCmd(name) {
    await withStore((store) => {
        const syms = store.findSymbol(name);
        if (syms.length === 0) {
            console.log('(no symbols match — try `openlife graph build` first)');
            return;
        }
        for (const s of syms) {
            console.log(`${s.exported ? '★' : ' '} [${s.kind}] ${s.name}  ${s.file}:${s.startLine}-${s.endLine}`);
        }
    });
}
async function callersCmd(name) {
    await withStore((store) => {
        const callers = store.findCallers(name);
        if (callers.length === 0) {
            console.log(`(no callers found for ${name})`);
            return;
        }
        for (const c of callers) {
            console.log(`${c.file}:${c.startLine} [${c.kind}] ${c.name}`);
        }
    });
}
async function depsCmd(file) {
    const { matches } = await resolveFileArg(file);
    if (matches.length === 0) {
        console.log(`(file "${file}" not found — try \`openlife graph build\` first, or pass an absolute path)`);
        process.exitCode = 1;
        return;
    }
    if (matches.length > 1) {
        console.log(`Multiple matches for "${file}". Pass an absolute path or a more specific suffix:`);
        for (const m of matches.slice(0, 10))
            console.log(`  ${m}`);
        if (matches.length > 10)
            console.log(`  …and ${matches.length - 10} more`);
        process.exitCode = 1;
        return;
    }
    const resolved = matches[0];
    await withStore((store) => {
        const edges = store.findDependencies(resolved);
        if (edges.length === 0) {
            console.log(`(no dependencies recorded for ${resolved})`);
            console.log('Either this file imports nothing, or the graph hasn\'t indexed it yet — run `openlife graph build`.');
            return;
        }
        console.log(`# dependencies of ${resolved}\n`);
        for (const e of edges) {
            // v1.14.1 — distinguish npm vs project edges, surface resolved abs path.
            const tag = e.resolvedFile
                ? `→ ${e.toModule}  (project, ${e.resolvedFile})`
                : `→ ${e.toModule}  (npm)`;
            console.log(`[${e.kind}] ${tag}`);
        }
    });
}
async function usagesCmd(name) {
    await withStore((store) => {
        const uses = store.findUsages(name);
        if (uses.length === 0) {
            console.log(`(no usages for ${name})`);
            return;
        }
        for (const u of uses) {
            console.log(`${u.file}:${u.startLine} [${u.kind}] ${u.name}`);
        }
    });
}
function registerGraphCommands(program) {
    const g = program
        .command('graph')
        .description('v1.14.0 — Codebase graph: symbols, dependencies, callers');
    g.command('build')
        .description('Walk the codebase and populate symbol + dependency DBs')
        .option('--root <path>', 'Project root (default: cwd)')
        .action((opts) => { void buildCmd(opts); });
    g.command('status')
        .description('Inspect symbol/edge counts')
        .action(() => { void statusCmd(); });
    g.command('find <name>')
        .description('Find symbols by exact name (or Class.method suffix)')
        .action((name) => { void findCmd(name); });
    g.command('callers <name>')
        .description('List symbols whose source file imports the file defining <name>')
        .action((name) => { void callersCmd(name); });
    g.command('deps <file>')
        .description('List dependencies of a source file (accepts abs / cwd-relative / bare filename)')
        .action((file) => { void depsCmd(file); });
    g.command('usages <name>')
        .description('Substring search across symbol names')
        .action((name) => { void usagesCmd(name); });
}
