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

import { parse } from 'yaml';
import type { TemplateValue } from './types.js';

export interface TemplateComposeDirective {
    id: string;
    args: Record<string, TemplateValue>;
}

export function parseTemplateComposeDirective(source: string): TemplateComposeDirective | undefined {
    const normalized = source.replace(/^\uFEFF/, '');
    const parsed = parse(normalized);
    if (!isRecord(parsed)) {
        return undefined;
    }
    const id = normalizeString(parsed.template);
    if (!id) {
        return undefined;
    }
    const args = parseArgs(parsed, ['template']);
    return { id, args };
}

function parseArgs(value: unknown, excludedKeys: string[] = []): Record<string, TemplateValue> {
    if (!isRecord(value)) {
        return {};
    }
    const excluded = new Set(excludedKeys);
    const args: Record<string, TemplateValue> = {};
    for (const [key, raw] of Object.entries(value)) {
        const normalizedKey = normalizeString(key);
        if (!normalizedKey || excluded.has(normalizedKey)) {
            continue;
        }
        const converted = toTemplateValue(raw);
        if (converted !== undefined) {
            args[normalizedKey] = converted;
        }
    }
    return args;
}

function toTemplateValue(value: unknown): TemplateValue | undefined {
    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 normalizeString(value: unknown): string | undefined {
    if (typeof value !== 'string') {
        return undefined;
    }
    const normalized = value.trim();
    return normalized.length > 0 ? normalized : undefined;
}

function isRecord(value: unknown): value is Record<string, unknown> {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
