/**
 * Every variant of `GeneralizedTaskDefinition` declares an optional
 * `context?: { docs?: GeneralizedDocRef[]; ... }`, so structural access
 * narrows correctly without an `as` cast. Returns `undefined` when the
 * task carries no doc refs.
 */
function taskContextDocs(task) {
    return task.context?.docs;
}
/**
 * `GeneralizedDocRef` is a 4-way union — only `SlugDocRef` and `IdDocRef`
 * carry a `slug`. Returns `undefined` for path / perspective refs.
 */
function docSlug(ref) {
    return "slug" in ref ? ref.slug : undefined;
}
/**
 * Only `IdDocRef` carries an `id`. Returns `undefined` for the other arms.
 */
function docId(ref) {
    return "id" in ref ? ref.id : undefined;
}
/**
 * Only `PathDocRef` and `IdDocRef` carry a `path`. Returns `undefined`
 * otherwise.
 */
function docPath(ref) {
    return "path" in ref ? ref.path : undefined;
}
/**
 * Does the changed-docs `entry` (a `GeneralizedDocRef`) match the task doc
 * `taskDoc` on the entry's strongest available key — `id`, then `path`,
 * then `slug`? Only the strongest key the entry carries is consulted; if
 * the entry has an `id` but the task doc has none, it does not fall through
 * to path/slug (a strong key, once chosen, is authoritative).
 */
function refMatchesTaskDoc(entry, taskDoc) {
    const entryId = docId(entry);
    if (entryId != null)
        return docId(taskDoc) === entryId;
    const entryPath = docPath(entry);
    if (entryPath != null)
        return docPath(taskDoc) === entryPath;
    const entrySlug = docSlug(entry);
    if (entrySlug != null)
        return docSlug(taskDoc) === entrySlug;
    // A perspective-only ref has no per-document match key; never matches a
    // single task doc here (perspective scoping is handled upstream).
    return false;
}
export function filterByChangedDocs(tasks, changedDocs) {
    if (!changedDocs || changedDocs.length === 0)
        return [...tasks];
    // Bare-string entries keep exact slug-match semantics via a Set lookup.
    const wantedSlugs = new Set(changedDocs.filter((d) => typeof d === "string"));
    const wantedRefs = changedDocs.filter((d) => typeof d !== "string");
    return tasks.filter((task) => {
        const docs = taskContextDocs(task);
        if (!docs || docs.length === 0)
            return false;
        return docs.some((taskDoc) => {
            const slug = docSlug(taskDoc);
            if (slug != null && wantedSlugs.has(slug))
                return true;
            return wantedRefs.some((entry) => refMatchesTaskDoc(entry, taskDoc));
        });
    });
}
