"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.machineRequirementExclusionsFileSchema = exports.requirementExclusionsSchema = exports.requirementExclusionEntrySchema = exports.CATALOG_REQUIREMENT_EXCLUSIONS_FILE_VERSION = void 0;
exports.normalizeRequirementExclusions = normalizeRequirementExclusions;
exports.normalizeRequirementExclusionEntry = normalizeRequirementExclusionEntry;
exports.requirementExclusionsFileToItems = requirementExclusionsFileToItems;
exports.emptyRequirementExclusions = emptyRequirementExclusions;
exports.emptyMachineRequirementExclusionsFile = emptyMachineRequirementExclusionsFile;
exports.findRequirementExclusionMatch = findRequirementExclusionMatch;
exports.buildRequirementExclusionHint = buildRequirementExclusionHint;
exports.buildRequirementExclusionHintForVisibleResult = buildRequirementExclusionHintForVisibleResult;
exports.compareRequirementExclusions = compareRequirementExclusions;
exports.compareRawRequirementExclusions = compareRawRequirementExclusions;
const zod_1 = require("zod");
exports.CATALOG_REQUIREMENT_EXCLUSIONS_FILE_VERSION = 1;
const REQUIREMENT_EXCLUSION_HINT_VISIBLE_THRESHOLD = 2;
exports.requirementExclusionEntrySchema = zod_1.z
    .object({
    ref: zod_1.z.string().trim().min(1).optional(),
    id: zod_1.z.string().trim().min(1).optional(),
    source: zod_1.z.string().trim().min(1).optional(),
    reason: zod_1.z.string().trim().min(1),
    addedAt: zod_1.z.string().trim().min(1).optional(),
})
    .strict()
    .superRefine((entry, context) => {
    if (entry.ref === undefined &&
        entry.id === undefined &&
        entry.source === undefined) {
        context.addIssue({
            code: "custom",
            path: ["ref"],
            message: "requirement exclusion entries must include at least one of ref, id, or source.",
        });
    }
});
exports.requirementExclusionsSchema = zod_1.z
    .object({
    skills: zod_1.z.array(exports.requirementExclusionEntrySchema).optional(),
    mcp: zod_1.z.array(exports.requirementExclusionEntrySchema).optional(),
})
    .strict();
exports.machineRequirementExclusionsFileSchema = zod_1.z
    .object({
    version: zod_1.z.literal(exports.CATALOG_REQUIREMENT_EXCLUSIONS_FILE_VERSION),
    requirementExclusions: exports.requirementExclusionsSchema,
})
    .strict();
function normalizeRequirementExclusions(exclusions) {
    return {
        skills: (exclusions?.skills ?? []).map(normalizeRequirementExclusionEntry),
        mcp: (exclusions?.mcp ?? []).map(normalizeRequirementExclusionEntry),
    };
}
function normalizeRequirementExclusionEntry(entry) {
    return {
        ...(entry.ref === undefined ? {} : { ref: entry.ref.trim() }),
        ...(entry.id === undefined ? {} : { id: entry.id.trim() }),
        ...(entry.source === undefined ? {} : { source: entry.source.trim() }),
        reason: entry.reason.trim(),
        ...(entry.addedAt === undefined ? {} : { addedAt: entry.addedAt.trim() }),
    };
}
function requirementExclusionsFileToItems(metadata, origin, filePath) {
    const exclusions = metadata === null
        ? emptyRequirementExclusions()
        : metadata.requirementExclusions;
    return [
        ...exclusions.skills.map((entry) => ({
            ...entry,
            target: "skill",
            origin,
            path: filePath,
        })),
        ...exclusions.mcp.map((entry) => ({
            ...entry,
            target: "mcp",
            origin,
            path: filePath,
        })),
    ];
}
function emptyRequirementExclusions() {
    return { skills: [], mcp: [] };
}
function emptyMachineRequirementExclusionsFile() {
    return {
        version: exports.CATALOG_REQUIREMENT_EXCLUSIONS_FILE_VERSION,
        requirementExclusions: emptyRequirementExclusions(),
    };
}
function findRequirementExclusionMatch(exclusions, target, candidate) {
    for (const exclusion of exclusions) {
        if (exclusion.target !== target) {
            continue;
        }
        const matchedBy = matchRequirementExclusion(exclusion, candidate);
        if (matchedBy === null) {
            continue;
        }
        return {
            reason: exclusion.reason,
            origin: exclusion.origin,
            path: exclusion.path,
            matchedBy,
        };
    }
    return null;
}
function buildRequirementExclusionHint(input) {
    if (input.excludedCount === 0) {
        return undefined;
    }
    const paths = [...new Set(input.paths)].sort();
    return {
        excludedCount: input.excludedCount,
        paths,
        message: `${input.excludedCount} candidate(s) were hidden because they are excluded from workflow requires. Re-run with --include-excluded to inspect them, or remove the matching entry from ${paths.join(", ")} after fixing local setup.`,
    };
}
function buildRequirementExclusionHintForVisibleResult(input) {
    if (input.hiddenMatches.length === 0 ||
        input.visibleCount > REQUIREMENT_EXCLUSION_HINT_VISIBLE_THRESHOLD) {
        return undefined;
    }
    return buildRequirementExclusionHint({
        excludedCount: input.hiddenMatches.length,
        paths: input.hiddenMatches.map((match) => match.path),
    });
}
function compareRequirementExclusions(left, right) {
    return (left.target.localeCompare(right.target) ||
        left.origin.localeCompare(right.origin) ||
        compareRawRequirementExclusions(left, right));
}
function compareRawRequirementExclusions(left, right) {
    return ((left.ref ?? "").localeCompare(right.ref ?? "") ||
        (left.id ?? "").localeCompare(right.id ?? "") ||
        (left.source ?? "").localeCompare(right.source ?? ""));
}
function matchRequirementExclusion(exclusion, candidate) {
    if (exclusion.ref !== undefined &&
        candidate.ref !== undefined &&
        candidate.ref !== null &&
        exclusion.ref === candidate.ref) {
        return "ref";
    }
    if (exclusion.id !== undefined &&
        candidate.id !== undefined &&
        candidate.id !== null &&
        exclusion.id === candidate.id) {
        return "id";
    }
    if (exclusion.source !== undefined &&
        candidate.source !== undefined &&
        candidate.source !== null &&
        exclusion.source === candidate.source) {
        return "source";
    }
    return null;
}
