function sliceLimit(limit) {
    return Math.max(1, limit);
}
function byUpdatedAtDesc(a, b) {
    return b.updatedAt - a.updatedAt || a.id.localeCompare(b.id);
}
function byCreatedAtDesc(a, b) {
    return b.createdAt - a.createdAt || a.id.localeCompare(b.id);
}
function byQueuedAtDesc(a, b) {
    return b.queuedAt - a.queuedAt || a.id.localeCompare(b.id);
}
function byRequestedAtDesc(a, b) {
    return (b.requestedAt - a.requestedAt) || a.id.localeCompare(b.id);
}
export function getKnowledgeStoreStatus(view) {
    return {
        ready: view.ready,
        storagePath: view.dbPath,
        sourceCount: view.sources.size,
        nodeCount: view.nodes.size,
        edgeCount: view.edges.size,
        issueCount: view.issues.size,
        extractionCount: view.extractions.size,
        jobRunCount: view.jobRuns.size,
        usageCount: view.usageRecords.size,
        candidateCount: view.consolidationCandidates.size,
        reportCount: view.consolidationReports.size,
        scheduleCount: view.schedules.size,
    };
}
export function listKnowledgeSources(view, limit = 100) {
    return [...view.sources.values()]
        .sort(byUpdatedAtDesc)
        .slice(0, sliceLimit(limit));
}
export function listKnowledgeNodes(view, limit = 100) {
    return [...view.nodes.values()]
        .sort(byUpdatedAtDesc)
        .slice(0, sliceLimit(limit));
}
export function listKnowledgeEdges(view) {
    return [...view.edges.values()];
}
export function listKnowledgeIssues(view, limit = 100) {
    return [...view.issues.values()]
        .sort(byUpdatedAtDesc)
        .slice(0, sliceLimit(limit));
}
export function listKnowledgeExtractions(view, limit = 100) {
    return [...view.extractions.values()]
        .sort(byUpdatedAtDesc)
        .slice(0, sliceLimit(limit));
}
export function listKnowledgeJobRuns(view, limit = 100, jobId) {
    return [...view.jobRuns.values()]
        .filter((run) => !jobId || run.jobId === jobId)
        .sort(byRequestedAtDesc)
        .slice(0, sliceLimit(limit));
}
export function listKnowledgeUsageRecords(view, limit = 100, input = {}) {
    return [...view.usageRecords.values()]
        .filter((record) => ((!input.targetKind || record.targetKind === input.targetKind)
        && (!input.targetId || record.targetId === input.targetId)
        && (!input.usageKind || record.usageKind === input.usageKind)))
        .sort(byCreatedAtDesc)
        .slice(0, sliceLimit(limit));
}
export function listKnowledgeConsolidationCandidates(view, limit = 100, input = {}) {
    return [...view.consolidationCandidates.values()]
        .filter((record) => ((!input.status || record.status === input.status)
        && (!input.subjectKind || record.subjectKind === input.subjectKind)
        && (!input.subjectId || record.subjectId === input.subjectId)))
        .sort((a, b) => b.score - a.score || b.updatedAt - a.updatedAt || a.id.localeCompare(b.id))
        .slice(0, sliceLimit(limit));
}
export function listKnowledgeConsolidationReports(view, limit = 100) {
    return [...view.consolidationReports.values()]
        .sort(byCreatedAtDesc)
        .slice(0, sliceLimit(limit));
}
export function listKnowledgeSchedules(view, limit = 100) {
    return [...view.schedules.values()]
        .sort((a, b) => a.label.localeCompare(b.label) || a.id.localeCompare(b.id))
        .slice(0, sliceLimit(limit));
}
export function getKnowledgeSource(view, id) {
    return view.sources.get(id) ?? null;
}
export function getKnowledgeNode(view, id) {
    return view.nodes.get(id) ?? null;
}
export function getKnowledgeIssue(view, id) {
    return view.issues.get(id) ?? null;
}
export function getKnowledgeExtraction(view, id) {
    return view.extractions.get(id) ?? null;
}
export function getKnowledgeExtractionBySourceId(view, sourceId) {
    for (const extraction of view.extractions.values()) {
        if (extraction.sourceId === sourceId)
            return extraction;
    }
    return null;
}
export function getKnowledgeJobRun(view, id) {
    return view.jobRuns.get(id) ?? null;
}
export function getKnowledgeUsageRecord(view, id) {
    return view.usageRecords.get(id) ?? null;
}
export function getKnowledgeConsolidationCandidate(view, id) {
    return view.consolidationCandidates.get(id) ?? null;
}
export function getKnowledgeConsolidationCandidateBySubject(view, subjectKind, subjectId, candidateType) {
    for (const candidate of view.consolidationCandidates.values()) {
        if (candidate.subjectKind === subjectKind && candidate.subjectId === subjectId && candidate.candidateType === candidateType) {
            return candidate;
        }
    }
    return null;
}
export function getKnowledgeConsolidationReport(view, id) {
    return view.consolidationReports.get(id) ?? null;
}
export function getKnowledgeSchedule(view, id) {
    return view.schedules.get(id) ?? null;
}
export function getKnowledgeSourceByCanonicalUri(view, canonicalUri) {
    for (const source of view.sources.values()) {
        if (source.canonicalUri === canonicalUri)
            return source;
    }
    return null;
}
export function getKnowledgeNodeByKindAndSlug(view, kind, slug) {
    for (const node of view.nodes.values()) {
        if (node.kind === kind && node.slug === slug)
            return node;
    }
    return null;
}
export function edgesForKnowledgeStore(view, kind, id) {
    return [...view.edges.values()].filter((edge) => ((edge.fromKind === kind && edge.fromId === id)
        || (edge.toKind === kind && edge.toId === id)));
}
export function getKnowledgeItem(view, id) {
    const source = getKnowledgeSource(view, id);
    const node = getKnowledgeNode(view, id);
    const issue = getKnowledgeIssue(view, id);
    if (!source && !node && !issue)
        return null;
    const relatedEdges = edgesForKnowledgeStore(view, source ? 'source' : 'node', id);
    const linkedSources = [];
    const linkedNodes = [];
    for (const edge of relatedEdges) {
        const otherKind = source
            ? edge.fromId === source.id && edge.fromKind === 'source'
                ? edge.toKind
                : edge.fromKind
            : edge.fromId === node?.id && edge.fromKind === 'node'
                ? edge.toKind
                : edge.fromKind;
        const otherId = source
            ? edge.fromId === source.id && edge.fromKind === 'source'
                ? edge.toId
                : edge.fromId
            : edge.fromId === node?.id && edge.fromKind === 'node'
                ? edge.toId
                : edge.fromId;
        if (otherKind === 'source') {
            const linked = getKnowledgeSource(view, otherId);
            if (linked)
                linkedSources.push(linked);
        }
        else if (otherKind === 'node') {
            const linked = getKnowledgeNode(view, otherId);
            if (linked)
                linkedNodes.push(linked);
        }
    }
    return { source: source ?? undefined, node: node ?? undefined, issue: issue ?? undefined, relatedEdges, linkedSources, linkedNodes };
}
