// Copyright (c) 2026 Modelware. All rights reserved.
import { extractLeadingFrontMatter } from '../md/md-frontmatter.js';
export function parseTemplateDefinition(content, sourceUri) {
    const frontMatter = extractLeadingFrontMatter(content);
    const data = frontMatter?.data;
    if (!data) {
        return undefined;
    }
    const rawTemplate = data.template;
    if (!isRecord(rawTemplate)) {
        return undefined;
    }
    const id = normalizeTemplateType(typeof rawTemplate.id === 'string' ? rawTemplate.id : '');
    if (!id) {
        return undefined;
    }
    const name = typeof rawTemplate.name === 'string' && rawTemplate.name.trim().length > 0
        ? rawTemplate.name.trim()
        : undefined;
    const rank = parseRank(rawTemplate.rank);
    const exposures = parseTemplateExposures(rawTemplate.expose);
    const parameters = parseTemplateParameters(rawTemplate.params);
    return {
        id,
        name,
        rank,
        exposures,
        parameters,
        body: content,
        sourceUri,
    };
}
export function deriveContextLabelFromIri(iri) {
    const normalized = iri.trim().replace(/^<|>$/g, '');
    if (!normalized) {
        return 'IRI';
    }
    const hashIndex = normalized.lastIndexOf('#');
    if (hashIndex >= 0 && hashIndex < normalized.length - 1) {
        return decodeIriSegment(normalized.slice(hashIndex + 1));
    }
    const withoutTrailingSlash = normalized.replace(/\/+$/, '');
    const slashIndex = withoutTrailingSlash.lastIndexOf('/');
    if (slashIndex >= 0 && slashIndex < withoutTrailingSlash.length - 1) {
        return decodeIriSegment(withoutTrailingSlash.slice(slashIndex + 1));
    }
    return decodeIriSegment(withoutTrailingSlash);
}
function normalizeTemplateType(value) {
    let normalized = value.trim();
    const wikilinkMatch = /^\[\[([^\]]+)\]\]$/.exec(normalized);
    if (wikilinkMatch) {
        normalized = (wikilinkMatch[1] ?? '').trim();
    }
    return normalized.replace(/^<|>$/g, '');
}
function parseTemplateExposures(raw) {
    const entries = Array.isArray(raw) ? raw : raw ? [raw] : [];
    const exposures = [];
    for (const entry of entries) {
        if (!isRecord(entry) || typeof entry.kind !== 'string') {
            continue;
        }
        const kind = entry.kind.trim();
        if (kind === 'navigation') {
            const match = isRecord(entry.match) ? entry.match : undefined;
            const anyTypeOf = asNormalizedStringArray(match?.anyTypeOf);
            const allTypesOf = asNormalizedStringArray(match?.allTypesOf);
            exposures.push({
                kind: 'navigation',
                match: (anyTypeOf.length > 0 || allTypesOf.length > 0)
                    ? { anyTypeOf, allTypesOf }
                    : undefined
            });
            continue;
        }
        if (kind === 'compose') {
            exposures.push({ kind: 'compose' });
            continue;
        }
        if (kind === 'call') {
            const selection = isRecord(entry.selection) ? entry.selection : undefined;
            const min = toNonNegativeInteger(selection?.min);
            const max = toNonNegativeInteger(selection?.max);
            exposures.push({
                kind: 'call',
                selection: min !== undefined || max !== undefined ? { min, max } : undefined
            });
        }
    }
    return exposures;
}
function parseTemplateParameters(raw) {
    if (!Array.isArray(raw)) {
        return [];
    }
    const params = [];
    for (const entry of raw) {
        if (!isRecord(entry)) {
            continue;
        }
        const id = typeof entry.id === 'string' ? entry.id.trim() : '';
        const type = typeof entry.type === 'string' ? entry.type.trim() : '';
        if (!id || !isSupportedParameterType(type)) {
            continue;
        }
        const required = typeof entry.required === 'boolean' ? entry.required : undefined;
        const fromValue = typeof entry.from === 'string' ? entry.from.trim() : '';
        const from = isSupportedBindingSource(fromValue) ? fromValue : undefined;
        const description = typeof entry.description === 'string' && entry.description.trim().length > 0
            ? entry.description.trim()
            : undefined;
        params.push({
            id,
            type,
            required,
            from,
            defaultValue: toTemplateValue(entry.defaultValue),
            description,
        });
    }
    return params;
}
function isSupportedParameterType(value) {
    return value === 'iri'
        || value === 'string'
        || value === 'number'
        || value === 'boolean'
        || value === 'iri[]'
        || value === 'json';
}
function isSupportedBindingSource(value) {
    return value === 'context.member'
        || value === 'context.ontology'
        || value === 'context.modelUri'
        || value === 'context.selection[*]'
        || /^context\.selection\[\d+]$/.test(value)
        || value === 'user';
}
function toTemplateValue(value) {
    if (value === null) {
        return null;
    }
    if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
        return value;
    }
    if (Array.isArray(value)) {
        return value.every((entry) => typeof entry === 'string') ? value : undefined;
    }
    if (isRecord(value)) {
        return value;
    }
    return undefined;
}
function parseRank(value) {
    if (typeof value === 'number' && Number.isFinite(value)) {
        return value;
    }
    if (typeof value === 'string') {
        const parsed = Number(value.trim());
        if (Number.isFinite(parsed)) {
            return parsed;
        }
    }
    return 0;
}
function asNormalizedStringArray(value) {
    if (!Array.isArray(value)) {
        return [];
    }
    return value
        .filter((entry) => typeof entry === 'string')
        .map((entry) => normalizeTemplateType(entry))
        .filter((entry) => entry.length > 0);
}
function toNonNegativeInteger(value) {
    if (typeof value === 'number' && Number.isInteger(value) && value >= 0) {
        return value;
    }
    if (typeof value === 'string') {
        const parsed = Number.parseInt(value.trim(), 10);
        if (Number.isInteger(parsed) && parsed >= 0) {
            return parsed;
        }
    }
    return undefined;
}
function isRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function decodeIriSegment(value) {
    if (!value) {
        return 'IRI';
    }
    try {
        return decodeURIComponent(value);
    }
    catch {
        return value;
    }
}
//# sourceMappingURL=definition.js.map