function isRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function normalizeRequiredString(value, field) {
    if (value == null) {
        throw new Error(`Strategy ${field} is required.`);
    }
    if (typeof value !== 'string') {
        throw new Error(`Strategy ${field} must be a string.`);
    }
    const trimmed = value.trim();
    if (!trimmed) {
        throw new Error(`Strategy ${field} is required.`);
    }
    return trimmed;
}
function assertPositiveNumber(value, field) {
    if (value == null)
        return;
    if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) {
        throw new Error(`Strategy ${field} must be a positive finite number.`);
    }
}
/**
 * defineStrategy is the stable author-facing DSL entry point. The runtime is
 * still evolving, but package consumers can already import this helper to
 * validate and type a strategy artifact consistently.
 */
export function defineStrategy(strategy) {
    if (!isRecord(strategy)) {
        throw new Error('Strategy definition is required.');
    }
    const name = normalizeRequiredString(strategy.name, 'name');
    if (!Array.isArray(strategy.universe) || strategy.universe.length === 0) {
        throw new Error('Strategy universe must include at least one instrument.');
    }
    const seen = new Set();
    const universe = strategy.universe.map((instrument, index) => {
        if (typeof instrument !== 'string') {
            throw new Error(`Strategy universe[${index}] must be a string.`);
        }
        const trimmed = instrument.trim();
        if (!trimmed) {
            throw new Error('Strategy universe cannot include empty instruments.');
        }
        if (seen.has(trimmed)) {
            throw new Error(`Strategy universe cannot include duplicate instrument: ${trimmed}.`);
        }
        seen.add(trimmed);
        return trimmed;
    });
    if (typeof strategy.signal !== 'function') {
        throw new Error('Strategy signal must be a function.');
    }
    let risk;
    if (strategy.risk !== undefined) {
        if (!isRecord(strategy.risk)) {
            throw new Error('Strategy risk must be an object.');
        }
        assertPositiveNumber(strategy.risk.maxNotionalUsd, 'risk.maxNotionalUsd');
        assertPositiveNumber(strategy.risk.maxDrawdownPct, 'risk.maxDrawdownPct');
        if (strategy.risk.killSwitch != null && typeof strategy.risk.killSwitch !== 'boolean') {
            throw new Error('Strategy risk.killSwitch must be a boolean when provided.');
        }
        risk = Object.freeze({ ...strategy.risk });
    }
    let schedule;
    if (strategy.schedule !== undefined) {
        if (!isRecord(strategy.schedule)) {
            throw new Error('Strategy schedule must be an object.');
        }
        const every = normalizeRequiredString(strategy.schedule.every, 'schedule.every');
        schedule = Object.freeze({ ...strategy.schedule, every });
    }
    let metadata;
    if (strategy.metadata !== undefined) {
        if (!isRecord(strategy.metadata)) {
            throw new Error('Strategy metadata must be an object.');
        }
        metadata = Object.freeze({ ...strategy.metadata });
    }
    return Object.freeze({
        ...strategy,
        name,
        universe: Object.freeze(universe),
        ...(risk ? { risk } : {}),
        ...(schedule ? { schedule } : {}),
        ...(metadata ? { metadata } : {}),
    });
}
