import path from 'node:path';
import { z } from 'zod';
import { documentToMarkdown } from '../markdown/convert.js';
import { detectCrossReferences } from '../doc/references.js';
import { inspectDocumentSummary } from '../doc/batch.js';
import { discoverDocumentSet } from '../doc/discover.js';
import { DEFAULT_EXCLUDE_DIRS, mapWithConcurrency } from '../utils.js';
/** Per-document inspection concurrency: integer >= 1, defaults to 4. */
export const DocumentSetConcurrencySchema = z.number().int().min(1).default(4);
export async function inspectWorkspaceDocumentSet(rootDir, options = {}, onProgress) {
    const resolvedRoot = path.resolve(rootDir);
    const excludeDir = options.excludeDir ?? [...DEFAULT_EXCLUDE_DIRS];
    const convertToMarkdown = options.convertToMarkdown ?? documentToMarkdown;
    const maxFiles = options.maxFiles ?? 50;
    const includeMarkdown = options.includeMarkdown ?? false;
    const maxReferenceFiles = options.maxReferenceFiles ?? 20;
    const concurrency = DocumentSetConcurrencySchema.parse(options.concurrency);
    const discovery = await discoverDocumentSet(resolvedRoot, {
        excludeDir,
        noGitignore: options.noGitignore,
        ignorePatterns: options.ignorePatterns,
        overlayIgnorePatterns: options.overlayIgnorePatterns,
        maxSizeBytes: (options.largeFileLimitMb ?? 50) * 1024 * 1024,
        includeDataFiles: options.includeDataFiles,
    });
    const discovered = discovery.documents.slice(0, maxFiles);
    const errors = [];
    const documents = [];
    const markdownByPath = new Map();
    const failedPaths = new Set();
    onProgress?.({
        phase: 'discover',
        total: discovered.length,
        completed: discovered.length,
        detail: discovered.length > 0 ? `${discovered.length} documents found` : 'No documents found',
    });
    if (discovered.length === 0) {
        return {
            schemaVersion: 1,
            rootDir: resolvedRoot,
            documents: [],
            crossReferences: [],
            unresolvedMentions: [],
            skipped: discovery.skipped,
            errors: [],
        };
    }
    // Inspect documents concurrently; progress uses a shared monotonic counter
    // (completion order may vary) while results, markdown, and errors are
    // assembled in discovery order after the join so output stays deterministic.
    let inspected = 0;
    const results = await mapWithConcurrency(discovered, concurrency, async (file) => {
        const result = await inspectDocumentSummary(file.filePath, file.relativePath, file.format, {
            includeMarkdown,
            convertToMarkdown,
        });
        onProgress?.({
            phase: 'inspect',
            total: discovered.length,
            completed: ++inspected,
            detail: file.relativePath,
            currentPath: file.filePath,
        });
        return result;
    });
    for (let i = 0; i < discovered.length; i++) {
        const file = discovered[i];
        const result = results[i];
        documents.push(result.summary);
        if (result.markdownContent) {
            markdownByPath.set(file.filePath, result.markdownContent);
        }
        if (result.error) {
            errors.push({
                path: file.filePath,
                message: result.error,
            });
            failedPaths.add(file.filePath);
        }
    }
    const docsWithContent = [];
    const refSlice = documents.slice(0, maxReferenceFiles);
    for (let i = 0; i < refSlice.length; i++) {
        const doc = refSlice[i];
        // Documents that already failed conversion during inspection are recorded
        // once above; skip them here so the failing parse is not retried.
        if (!failedPaths.has(doc.filePath)) {
            try {
                const content = doc.markdownContent ?? markdownByPath.get(doc.filePath) ?? (await convertToMarkdown(doc.filePath));
                if (content)
                    docsWithContent.push({ filePath: doc.filePath, content });
            }
            catch (err) {
                const error = err;
                errors.push({
                    path: doc.filePath,
                    message: error.message,
                });
                failedPaths.add(doc.filePath);
            }
        }
        onProgress?.({
            phase: 'references',
            total: refSlice.length,
            completed: i + 1,
            detail: path.relative(resolvedRoot, doc.filePath).split(path.sep).join('/'),
            currentPath: doc.filePath,
        });
    }
    const references = docsWithContent.length >= 2 ? detectCrossReferences(docsWithContent) : { references: [], unresolvedMentions: [] };
    onProgress?.({
        phase: 'cross-references',
        total: 1,
        completed: 1,
        detail: `${references.references.length} cross-references detected`,
    });
    return {
        schemaVersion: 1,
        rootDir: resolvedRoot,
        documents,
        crossReferences: references.references,
        unresolvedMentions: references.unresolvedMentions,
        skipped: discovery.skipped,
        errors,
    };
}
//# sourceMappingURL=documents.js.map