const MAX_GAPS = 3;
export function detectDecisionGaps(signals, _projectContext) {
    const gaps = [
        buildPermissionGap(signals),
        buildProviderGap(signals),
        buildBillingModelGap(signals),
        buildDataGap(signals),
        buildFailureGap(signals),
    ].filter((gap) => gap !== null);
    if (gaps.length === 0 && !signals.hasScope) {
        gaps.push(buildBehaviorGap(signals));
    }
    return gaps.slice(0, MAX_GAPS);
}
function buildPermissionGap(signals) {
    if (!signals.hasPermissionRisk || signals.actors.length > 0) {
        return null;
    }
    const subject = formatSubject(signals);
    return makeGap({
        id: 'permission-owner',
        kind: 'permission',
        header: 'Permission',
        question: `For ${subject}, who is allowed to perform this action? This changes permissions, validation, and audit behavior.`,
        evidence: evidenceFrom(signals, ['permission-sensitive wording']),
        impact: 'Changes authorization checks and acceptance criteria.',
        options: options([
            ['Role-based owner (Recommended)', 'Use the existing role or owner model for this action.'],
            ['Admin only', 'Restrict the behavior to administrators.'],
            ['Any signed-in user', 'Allow all authenticated users and keep checks minimal.'],
        ]),
    });
}
function buildProviderGap(signals) {
    if (!signals.hasBilling || signals.namedProvider !== null) {
        return null;
    }
    const subject = formatSubject(signals);
    return makeGap({
        id: 'payment-provider',
        kind: 'provider',
        header: 'Provider',
        question: `For ${subject}, which payment provider should own the payment flow? This changes API contracts, webhook handling, and test fixtures.`,
        evidence: evidenceFrom(signals, ['billing/payment wording']),
        impact: 'Changes integration code, webhook behavior, and verification fixtures.',
        options: options([
            ['Stripe (Recommended)', 'Use the most common provider for subscription and checkout flows.'],
            ['PayPal', 'Use PayPal checkout and payment APIs.'],
            [
                'No provider yet',
                'Keep provider integration out of scope and define internal contracts only.',
            ],
        ]),
    });
}
function buildBillingModelGap(signals) {
    if (!signals.hasBilling) {
        return null;
    }
    const subject = formatSubject(signals);
    return makeGap({
        id: 'billing-model',
        kind: 'billing-model',
        header: 'Billing',
        question: `For ${subject}, is the billing behavior recurring, one-time, or invoice-based? This changes states, events, and acceptance criteria.`,
        evidence: evidenceFrom(signals, ['billing/payment wording']),
        impact: 'Changes lifecycle states and acceptance criteria.',
        options: options([
            ['Recurring subscription (Recommended)', 'Model ongoing subscriptions and renewal states.'],
            ['One-time checkout', 'Model a single payment completion flow.'],
            ['Invoice-based', 'Model invoice creation, payment, and overdue states.'],
        ]),
    });
}
function buildDataGap(signals) {
    if (!signals.hasDatabase || signals.dataObjects.length > 0) {
        return null;
    }
    const subject = formatSubject(signals);
    return makeGap({
        id: 'data-shape',
        kind: 'data',
        header: 'Data',
        question: `For ${subject}, what data must be stored or updated? This changes schema, validation, and migration work.`,
        evidence: evidenceFrom(signals, ['database/data wording']),
        impact: 'Changes schema, persistence, and validation requirements.',
        options: options([
            [
                'Existing records only (Recommended)',
                'Use existing tables or records without a new schema.',
            ],
            ['New table or field', 'Add persistence changes and migration coverage.'],
            ['Read-only data', 'Do not persist new state for this behavior.'],
        ]),
    });
}
function buildFailureGap(signals) {
    if (signals.integrations.length === 0 &&
        !signals.riskTerms.includes('sync') &&
        !signals.riskTerms.includes('api')) {
        return null;
    }
    const subject = formatSubject(signals);
    return makeGap({
        id: 'failure-handling',
        kind: 'failure',
        header: 'Failure',
        question: `For ${subject}, what should happen if ${formatIntegration(signals)} fails? This changes retry, error, and user-visible behavior.`,
        evidence: evidenceFrom(signals, signals.integrations.length > 0 ? signals.integrations : ['integration/API wording']),
        impact: 'Changes error handling, retries, and tests.',
        options: options([
            ['Show recoverable error (Recommended)', 'Return a clear error and preserve current state.'],
            ['Retry automatically', 'Retry transient failures before surfacing an error.'],
            ['Queue for later', 'Persist work for asynchronous retry.'],
        ]),
    });
}
function buildBehaviorGap(signals) {
    const subject = formatSubject(signals);
    return makeGap({
        id: 'behavior-outcome',
        kind: 'behavior',
        header: 'Behavior',
        question: `For ${subject}, what observable outcome should prove the work is done? This becomes the primary acceptance criterion.`,
        evidence: evidenceFrom(signals, ['short request']),
        impact: 'Changes the main acceptance criterion and verification command.',
        options: options([
            ['User-visible workflow (Recommended)', 'Define the end-to-end behavior a user can observe.'],
            ['Backend behavior', 'Define API, persistence, job, or integration behavior.'],
            ['Cleanup or fix', 'Define the before/after bug or cleanup result.'],
        ]),
    });
}
function makeGap(gap) {
    return { ...gap, multiSelect: gap.multiSelect ?? false, blocking: true };
}
function formatSubject(signals) {
    const action = signals.action ?? 'this request';
    const object = signals.domainObject;
    return object === null ? action : `${action} ${object}`;
}
function formatIntegration(signals) {
    if (signals.integrations.length > 0) {
        return signals.integrations[0] ?? 'the integration';
    }
    if (signals.riskTerms.includes('sync')) {
        return 'the sync';
    }
    return 'the API';
}
function evidenceFrom(signals, extra) {
    return [
        ...(signals.action ? [`action:${signals.action}`] : []),
        ...(signals.domainObject ? [`object:${signals.domainObject}`] : []),
        ...signals.riskTerms.map((term) => `risk:${term}`),
        ...extra,
    ].slice(0, 6);
}
function options(items) {
    return items.map(([label, description]) => ({ label, description }));
}
//# sourceMappingURL=decision-gap-detector.js.map