// Copyright (c) 2026 Modelware. All rights reserved.

import type { TemplateBindResult, TemplateDefinition, TemplateInvocationContext, TemplateParameterDefinition, TemplateValue } from './types.js';

export function bindTemplateParameters(
    template: TemplateDefinition,
    context: TemplateInvocationContext,
    explicitArgs: Readonly<Record<string, TemplateValue>> = {}
): TemplateBindResult {
    const values: Record<string, TemplateValue> = {};
    const missingRequired: string[] = [];
    const parameters = template.parameters ?? [];
    for (const parameter of parameters) {
        const explicit = explicitArgs[parameter.id];
        if (explicit !== undefined) {
            values[parameter.id] = explicit;
            continue;
        }
        const bound = resolveValueFromContext(parameter, context);
        if (bound !== undefined) {
            values[parameter.id] = bound;
            continue;
        }
        if (parameter.defaultValue !== undefined) {
            values[parameter.id] = parameter.defaultValue;
            continue;
        }
        if (parameter.required) {
            missingRequired.push(parameter.id);
        }
    }
    return { values, missingRequired };
}

function resolveValueFromContext(
    parameter: TemplateParameterDefinition,
    context: TemplateInvocationContext
): TemplateValue | undefined {
    switch (parameter.from) {
        case 'context.member':
            return context.focus?.memberIri;
        case 'context.ontology':
            return context.model?.ontologyIri;
        case 'context.modelUri':
            return context.model?.modelUri;
        case 'context.selection[*]':
            return context.selection?.iris ?? [];
        default:
            return resolveSelectionIndexedBinding(parameter.from, context);
    }
}

function resolveSelectionIndexedBinding(
    source: TemplateParameterDefinition['from'],
    context: TemplateInvocationContext
): TemplateValue | undefined {
    if (!source || !source.startsWith('context.selection[')) {
        return undefined;
    }
    const match = /^context\.selection\[(\d+)]$/.exec(source);
    if (!match) {
        return undefined;
    }
    const index = Number.parseInt(match[1] ?? '', 10);
    if (!Number.isFinite(index) || index < 0) {
        return undefined;
    }
    const iris = context.selection?.iris ?? [];
    return iris[index];
}
