"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_SPEC_SEARCH_STATUS = void 0;
exports.selectDefaultSpecSearchEntries = selectDefaultSpecSearchEntries;
exports.searchSpecRegistryEntries = searchSpecRegistryEntries;
exports.mapSpecSearchEntries = mapSpecSearchEntries;
exports.filterSpecSearchEntries = filterSpecSearchEntries;
exports.renderDefaultSpecSearchText = renderDefaultSpecSearchText;
exports.buildSpecSearchRecoveryCommand = buildSpecSearchRecoveryCommand;
const list_1 = require("./list");
exports.DEFAULT_SPEC_SEARCH_STATUS = "active";
function selectDefaultSpecSearchEntries(document, options = {}) {
    return (0, list_1.selectVisibleSpecRegistryEntries)(document, options).entries;
}
function searchSpecRegistryEntries(document, query, options = {}) {
    const visibility = (0, list_1.selectVisibleSpecRegistryEntries)(document, options);
    const entries = filterSpecSearchEntries(mapSpecSearchEntries(visibility.entries), query);
    const allQueryMatches = filterSpecSearchEntries(mapSpecSearchEntries(document.entries), query);
    const appliedStatusSet = new Set(visibility.appliedStatuses);
    const excludedMatches = allQueryMatches.filter((entry) => (!appliedStatusSet.has(normalizeSpecSearchStatus(entry.status))));
    const excludedMatchStatusCounts = (0, list_1.countSpecRegistryStatuses)(document.entries.filter((entry) => (excludedMatches.some((match) => match.id === entry.id && match.specPath === entry.spec_path))));
    const recoveryStatuses = (0, list_1.normalizeSpecRegistryStatuses)(excludedMatches.map((entry) => entry.status));
    return {
        visibility,
        entries,
        excludedMatches,
        excludedMatchStatusCounts,
        recoveryStatuses,
        recoveryCommand: excludedMatches.length === 0 || normalizeSpecSearchQuery(query).length === 0
            ? null
            : buildSpecSearchRecoveryCommand(query, recoveryStatuses),
        resultEntries: entries.length,
        excludedMatchEntries: excludedMatches.length
    };
}
function mapSpecSearchEntries(entries) {
    return entries.map((entry) => {
        const searchEntry = {
            id: entry.id,
            title: entry.title,
            status: entry.status,
            specPath: entry.spec_path,
            sourceType: entry.source.type,
            sourceReference: entry.source.ref
        };
        if (entry.depth !== undefined) {
            searchEntry.depth = entry.depth;
        }
        if (entry.destination !== undefined) {
            searchEntry.destination = entry.destination;
        }
        if (entry.optional.linked_slice !== undefined) {
            searchEntry.linkedSlice = entry.optional.linked_slice;
        }
        return searchEntry;
    });
}
function filterSpecSearchEntries(entries, query) {
    const normalizedQuery = normalizeSpecSearchQuery(query);
    if (normalizedQuery.length === 0) {
        return entries;
    }
    return entries.filter((entry) => {
        const searchableFields = getSpecSearchableFields(entry);
        return searchableFields.some((fieldValue) => fieldValue.toLocaleLowerCase().includes(normalizedQuery));
    });
}
function normalizeSpecSearchQuery(query) {
    return String(query ?? "").trim().toLocaleLowerCase();
}
function normalizeSpecSearchStatus(status) {
    return String(status).trim().toLocaleLowerCase();
}
function getSpecSearchableFields(entry) {
    const fields = [
        entry.id,
        entry.title,
        entry.status,
        entry.specPath,
        entry.sourceType,
        entry.sourceReference
    ];
    if (entry.depth !== undefined) {
        fields.push(entry.depth);
    }
    if (entry.destination !== undefined) {
        fields.push(entry.destination);
    }
    if (entry.linkedSlice !== undefined) {
        fields.push(entry.linkedSlice.slice);
        fields.push(entry.linkedSlice.path);
    }
    return fields;
}
function renderDefaultSpecSearchText(entries, options = {}, result) {
    const evidence = result === undefined
        ? []
        : [
            ...(0, list_1.renderSpecRegistryVisibilityEvidence)(result.visibility),
            `Query result entries: ${result.resultEntries}`,
            `Excluded query matches: ${result.excludedMatchEntries}`,
            `Excluded match status counts: ${formatStatusCounts(result.excludedMatchStatusCounts)}`
        ];
    const entryText = entries.length === 0
        ? renderEmptySpecSearchText(options, result)
        : renderSpecSearchEntries(entries);
    return evidence.length === 0
        ? entryText
        : `${evidence.join("\n")}\n\n${entryText}`;
}
function buildSpecSearchRecoveryCommand(query, statuses) {
    const normalizedQuery = String(query ?? "").trim();
    const normalizedStatuses = (0, list_1.normalizeSpecRegistryStatuses)(statuses);
    if (normalizedQuery.length === 0 || normalizedStatuses.length === 0) {
        return null;
    }
    const statusArguments = normalizedStatuses
        .map((status) => `--status ${quoteCommandArgument(status)}`)
        .join(" ");
    return `day-shift spec search ${quoteCommandArgument(normalizedQuery)} ${statusArguments}`;
}
function renderSpecSearchEntries(entries) {
    return entries
        .map((entry, index) => {
        const lines = [
            `[${index + 1}] ${entry.id}`,
            `  title: ${entry.title}`,
            `  status: ${entry.status}`,
            `  spec path: ${entry.specPath}`,
            `  source type: ${entry.sourceType}`,
            `  source reference: ${entry.sourceReference}`
        ];
        if (entry.depth !== undefined) {
            lines.splice(2, 0, `  depth: ${entry.depth}`);
        }
        if (entry.destination !== undefined) {
            const statusIndex = lines.findIndex((line) => line.startsWith("  status:"));
            lines.splice(statusIndex + 1, 0, `  destination: ${entry.destination}`);
        }
        if (entry.linkedSlice !== undefined) {
            lines.push(`  linked slice: ${entry.linkedSlice.slice}`);
            lines.push(`  linked slice path: ${entry.linkedSlice.path}`);
        }
        return lines.join("\n");
    })
        .join("\n\n");
}
function renderEmptySpecSearchText(options, result) {
    if (result?.excludedMatchEntries) {
        return [
            "No query matches were visible under the applied lifecycle statuses.",
            `Matching entries excluded by status: ${result.excludedMatchEntries}.`,
            `Rerun: ${result.recoveryCommand}`
        ].join("\n");
    }
    if (result !== undefined) {
        return "No spec registry entries matched the query across available lifecycle statuses.";
    }
    if (options.includeArchived) {
        return "No spec registry entries found.";
    }
    return "No non-archived spec registry entries found.";
}
function formatStatusCounts(counts) {
    const entries = Object.entries(counts);
    return entries.length === 0
        ? "none"
        : entries.map(([status, count]) => `${status}=${count}`).join(", ");
}
function quoteCommandArgument(value) {
    if (/^[A-Za-z0-9_./:@+-]+$/.test(value)) {
        return value;
    }
    return `'${value.replace(/'/g, `'"'"'`)}'`;
}
