import { normalizeLabel } from '../util/text.js';
const TECHNOLOGY_ONTOLOGY = [
    {
        value: 'frontend',
        children: [
            { value: 'react', children: [{ value: 'next' }] },
            { value: 'typescript' },
            { value: 'javascript' },
        ],
    },
    {
        value: 'backend',
        children: [
            { value: 'node' },
            { value: 'typescript' },
            { value: 'python' },
            { value: 'go' },
            { value: 'rust' },
        ],
    },
    {
        value: 'db',
        children: [
            { value: 'postgres', children: [{ value: 'pgvector' }] },
            { value: 'redis' },
        ],
    },
    {
        value: 'infra',
        children: [
            { value: 'docker' },
            { value: 'aws', children: [{ value: 'lambda' }, { value: 'serverless' }] },
        ],
    },
    {
        value: 'protocol',
        children: [
            { value: 'mcp' },
            { value: 'graphql' },
            { value: 'rest' },
        ],
    },
];
const BUSINESS_AREA_ONTOLOGY = [
    {
        value: 'auth',
        children: [
            { value: 'login' },
            { value: 'token' },
            { value: 'session' },
        ],
    },
    {
        value: 'billing',
        children: [
            { value: 'subscription' },
            { value: 'paywall' },
            { value: 'invoice' },
        ],
    },
    {
        value: 'search',
        children: [
            { value: 'retrieval' },
            { value: 'ranking' },
        ],
    },
    {
        value: 'content',
        children: [
            { value: 'newsletter' },
            { value: 'publishing' },
            { value: 'media' },
        ],
    },
    {
        value: 'engagement',
        children: [
            { value: 'analytics' },
            { value: 'notification' },
            { value: 'profile' },
        ],
    },
    {
        value: 'ads',
    },
];
const DOMAIN_ONTOLOGY = [
    {
        value: 'infra',
        children: [
            { value: 'docker' },
            { value: 'ci' },
            { value: 'build' },
        ],
    },
    {
        value: 'storage',
        children: [
            { value: 'postgres' },
            { value: 'redis' },
        ],
    },
    {
        value: 'observability',
        children: [
            { value: 'logging' },
            { value: 'metrics' },
            { value: 'tracing' },
        ],
    },
];
const ONTOLOGY_BY_AXIS = {
    technology: TECHNOLOGY_ONTOLOGY,
    business_area: BUSINESS_AREA_ONTOLOGY,
    domain: DOMAIN_ONTOLOGY,
};
const ANCESTOR_INDICES = {};
function indexForAxis(axis) {
    const cached = ANCESTOR_INDICES[axis];
    if (cached)
        return cached;
    const index = new Map();
    for (const root of ONTOLOGY_BY_AXIS[axis]) {
        walkOntology(root, [], index);
    }
    ANCESTOR_INDICES[axis] = index;
    return index;
}
function walkOntology(node, parentChain, index) {
    const key = normalizeLabel(node.value);
    const existing = index.get(key);
    if (!existing) {
        index.set(key, [...parentChain]);
    }
    for (const child of node.children ?? []) {
        walkOntology(child, [...parentChain, node.value], index);
    }
}
export function ontologyAxisFromLabelType(type) {
    if (type === 'technology' || type === 'business_area' || type === 'domain') {
        return type;
    }
    return undefined;
}
export function expandOntologyValue(axis, value) {
    const leaf = normalizeLabel(value);
    const index = indexForAxis(axis);
    const ancestors = index.get(leaf);
    if (!ancestors) {
        return { leaf, ancestors: [], matched: false };
    }
    // Index stores parent chain from root → leaf. We return ancestors ordered closest-first
    // so callers can attenuate by distance with index-as-distance semantics.
    return {
        leaf,
        ancestors: [...ancestors].reverse().map((ancestor) => normalizeLabel(ancestor)),
        matched: true,
    };
}
/**
 * Expand each ontology-aware label (technology / business_area / domain) to include its
 * normalized ancestors. Ancestors are added with reduced weight + `provenance.source='ontology'`
 * so the original leaf label still dominates ranking. Non-ontology labels pass through unchanged.
 */
export function expandLabelsThroughOntology(labels, options = {}) {
    if (options.enabled === false) {
        return labels;
    }
    const seen = new Set();
    const result = [];
    for (const label of labels) {
        const key = `${label.type}:${normalizeLabel(label.value)}`;
        if (!seen.has(key)) {
            seen.add(key);
            result.push(label);
        }
        const axis = ontologyAxisFromLabelType(label.type);
        if (!axis)
            continue;
        const expansion = expandOntologyValue(axis, label.value);
        if (!expansion.matched)
            continue;
        for (let i = 0; i < expansion.ancestors.length; i += 1) {
            const ancestor = expansion.ancestors[i];
            const ancestorKey = `${label.type}:${ancestor}`;
            if (seen.has(ancestorKey))
                continue;
            seen.add(ancestorKey);
            // Closer ancestors keep more weight than far ones; never above the leaf.
            const ancestorWeight = Math.max(0.3, (label.weight ?? 0.75) * (0.7 - i * 0.1));
            result.push({
                type: label.type,
                value: ancestor,
                weight: Math.min(label.weight ?? 0.75, ancestorWeight),
                provenance: { source: 'ontology', confidence: Math.max(0.4, 0.85 - i * 0.1) },
            });
        }
    }
    return result;
}
/** True when `candidateValue` is an ancestor of `leafValue` under `axis`, or equal to it. */
export function isOntologyMatch(axis, leafValue, candidateValue) {
    const target = normalizeLabel(candidateValue);
    const leaf = normalizeLabel(leafValue);
    if (target === leaf)
        return true;
    const expansion = expandOntologyValue(axis, leafValue);
    return expansion.matched && expansion.ancestors.includes(target);
}
