// tools/cross-repo-search-handler.ts — SPEC-296: Handlers for cross-repo search tools.
import { addProject, removeProject, getProjects, saveRegistry, getRegistry, } from '../storage/global-projects-store.js';
import { listSpecs } from '../storage/spec-store.js';
import { hashProjectPath } from '../storage/base-store.js';
import { searchAcrossProjects } from '../engine/cross-repo-searcher.js';
// ---------------------------------------------------------------------------
// register_project_path
// ---------------------------------------------------------------------------
/**
 * Register a project path so it participates in cross-repo search.
 *
 * After persisting the entry, eagerly refresh `specCount` by reading the
 * project's `specs.json` via the cwd-tolerant store (which walks ancestor
 * directories when the cwd-relative file is missing). This unblocks downstream
 * tools that previously trusted the cached `specCount: 0` and reported the
 * project as empty even when 21 specs were on disk.
 */
export async function handleRegisterProjectPath(input) {
    const { projectPath } = input;
    const entry = await addProject(projectPath);
    let scanNote = '';
    try {
        const specs = await listSpecs(entry.hash);
        if (specs.length !== entry.specCount) {
            const registry = await getRegistry();
            const target = registry.projects.find((p) => p.path === entry.path);
            if (target !== undefined) {
                target.specCount = specs.length;
                target.lastScanAt = new Date().toISOString();
                registry.updatedAt = new Date().toISOString();
                await saveRegistry(registry);
            }
        }
        scanNote = ` — ${String(specs.length)} spec(s) detected on disk`;
    }
    catch {
        /* best-effort — registration must succeed even if spec scan fails */
    }
    return {
        content: [
            {
                type: 'text',
                text: `Project registered: ${entry.path} (hash: ${entry.hash})${scanNote}`,
            },
        ],
    };
}
// ---------------------------------------------------------------------------
// unregister_project_path
// ---------------------------------------------------------------------------
/**
 * Remove a project path from the cross-repo registry.
 */
export async function handleUnregisterProjectPath(input) {
    const { projectPath } = input;
    const removed = await removeProject(projectPath);
    if (!removed) {
        return {
            content: [
                {
                    type: 'text',
                    text: `Project not found in registry: ${projectPath}`,
                },
            ],
            isError: true,
        };
    }
    return {
        content: [
            {
                type: 'text',
                text: `Project unregistered: ${projectPath}`,
            },
        ],
    };
}
// ---------------------------------------------------------------------------
// list_registered_projects
// ---------------------------------------------------------------------------
/**
 * List all registered projects with their spec counts.
 */
export async function handleListRegisteredProjects(_input) {
    const projects = await getProjects();
    if (projects.length === 0) {
        return {
            content: [
                {
                    type: 'text',
                    text: 'No projects registered. Use register_project_path to add projects.',
                },
            ],
        };
    }
    const lines = projects.map((p) => `- ${p.path} (${String(p.specCount)} specs, registered: ${p.registeredAt}${p.lastScanAt !== undefined ? `, last scan: ${p.lastScanAt}` : ''})`);
    return {
        content: [
            {
                type: 'text',
                text: `Registered projects (${String(projects.length)}):\n${lines.join('\n')}`,
            },
        ],
    };
}
// ---------------------------------------------------------------------------
// search_all_projects
// ---------------------------------------------------------------------------
/**
 * Search specs across all registered projects.
 * Projects that fail to load are counted but do not abort the search.
 */
export async function handleSearchAllProjects(input) {
    const projects = await getProjects();
    if (projects.length === 0) {
        return {
            content: [
                {
                    type: 'text',
                    text: 'No projects registered. Use register_project_path to add projects first.',
                },
            ],
        };
    }
    const registry = await getRegistry();
    const bundles = [];
    let failedCount = 0;
    for (const project of projects) {
        try {
            const projectId = hashProjectPath(project.path);
            const specs = await listSpecs(projectId);
            bundles.push({ projectPath: project.path, projectHash: project.hash, specs });
            // Update spec count in registry
            const entry = registry.projects.find((p) => p.path === project.path);
            if (entry !== undefined) {
                entry.specCount = specs.length;
                entry.lastScanAt = new Date().toISOString();
            }
        }
        catch {
            failedCount += 1;
        }
    }
    // Persist updated counts — fire-and-forget
    registry.updatedAt = new Date().toISOString();
    saveRegistry(registry).catch((err) => {
        console.error('[Planu] Failed to update registry spec counts:', err);
    });
    const response = searchAcrossProjects(bundles, input);
    const finalResponse = { ...response, failedProjects: failedCount };
    if (finalResponse.total === 0) {
        return {
            content: [
                {
                    type: 'text',
                    text: `No specs found matching the given filters across ${String(finalResponse.scannedProjects)} project(s).` +
                        (failedCount > 0 ? ` (${String(failedCount)} project(s) failed to load)` : ''),
                },
            ],
        };
    }
    const lines = finalResponse.items.map((r) => `[${r.projectPath}] ${r.specId}: ${r.title} (${r.status}, score: ${r.matchScore.toFixed(2)})`);
    const summary = [
        `Found ${String(finalResponse.total)} spec(s) across ${String(finalResponse.scannedProjects)} project(s)${failedCount > 0 ? ` (${String(failedCount)} failed)` : ''}:`,
        ...lines,
    ].join('\n');
    return {
        content: [
            {
                type: 'text',
                text: summary,
            },
        ],
    };
}
//# sourceMappingURL=cross-repo-search-handler.js.map