import { existsSync, readdirSync, statSync } from 'node:fs';
import { join } from 'node:path';
import { getConfigPath } from '../config/paths.js';
import { parseCustomToolFile } from '../custom-tools/parser.js';
import { formatError } from '../utils/error-formatter.js';
function isSafeEntry(entry) {
    return (entry !== '..' &&
        entry !== '.' &&
        !entry.includes('/') &&
        !entry.includes('\\'));
}
/**
 * Scans `.nanocoder/tools/` (project) and the personal tools dir for `.md`
 * custom-tool files. Personal first, project second so project files shadow
 * personal ones by `name`. Duplicate names within the same directory: the
 * first wins, the second is logged as an error.
 *
 * `.ts`/`.js` files are deliberately ignored — Phase 2 will pick them up.
 */
export class CustomToolLoader {
    projectRoot;
    projectToolsDir;
    personalToolsDir;
    errors = [];
    constructor(projectRoot = process.cwd()) {
        this.projectRoot = projectRoot;
        this.projectToolsDir = join(projectRoot, '.nanocoder', 'tools');
        this.personalToolsDir = join(getConfigPath(), 'tools');
    }
    getProjectToolsDirectory() {
        return this.projectToolsDir;
    }
    getPersonalToolsDirectory() {
        return this.personalToolsDir;
    }
    getProjectRoot() {
        return this.projectRoot;
    }
    hasCustomTools() {
        return (existsSync(this.projectToolsDir) || existsSync(this.personalToolsDir));
    }
    getErrors() {
        return [...this.errors];
    }
    /**
     * Discover and parse all custom tools. Project entries override personal
     * ones by name. Returns the merged set plus any per-file errors that
     * occurred.
     */
    load() {
        this.errors = [];
        const byName = new Map();
        const personal = this.scanDirectory(this.personalToolsDir, 'personal');
        for (const t of personal) {
            if (byName.has(t.metadata.name)) {
                this.errors.push({
                    file: t.filePath,
                    error: `Duplicate tool name "${t.metadata.name}" in personal tools directory — keeping the first.`,
                });
                continue;
            }
            byName.set(t.metadata.name, t);
        }
        const project = this.scanDirectory(this.projectToolsDir, 'project');
        const seenInProject = new Set();
        for (const t of project) {
            if (seenInProject.has(t.metadata.name)) {
                this.errors.push({
                    file: t.filePath,
                    error: `Duplicate tool name "${t.metadata.name}" in project tools directory — keeping the first.`,
                });
                continue;
            }
            seenInProject.add(t.metadata.name);
            // Project tools always override personal ones — no error.
            byName.set(t.metadata.name, t);
        }
        return { tools: Array.from(byName.values()), errors: this.getErrors() };
    }
    scanDirectory(dir, source) {
        if (!existsSync(dir))
            return [];
        const out = [];
        let entries;
        try {
            entries = readdirSync(dir);
        }
        catch (err) {
            this.errors.push({ file: dir, error: String(err) });
            return [];
        }
        for (const entry of entries) {
            if (!isSafeEntry(entry))
                continue;
            if (!entry.endsWith('.md'))
                continue;
            const fullPath = join(dir, entry);
            let stat;
            try {
                stat = statSync(fullPath);
            }
            catch {
                continue;
            }
            if (!stat.isFile())
                continue;
            try {
                const parsed = parseCustomToolFile(fullPath);
                out.push({
                    metadata: parsed.metadata,
                    body: parsed.body,
                    filePath: fullPath,
                    source,
                    subscribe: parsed.subscribe,
                });
            }
            catch (err) {
                this.errors.push({
                    file: fullPath,
                    error: formatError(err),
                });
            }
        }
        return out;
    }
}
//# sourceMappingURL=loader.js.map