/**
 * Rule: cascade-integrity
 *
 * For every `hasMany ... cascade` relationship, deleting the parent must
 * delete its children. Scenario:
 *
 *   1. create the parent (top-level),
 *   2. create a child with its FK pointing at the parent,
 *   3. delete the parent,
 *   4. assert the child is gone (retrieve → rejected).
 *
 * Scope (v1): the child must have exactly one belongsTo (→ this parent) so
 * it can be seeded from just the parent's id. Multi-parent children (e.g.
 * poll-app's Vote → Poll + Option) need topological seeding (later phase).
 * Both models' controllers must expose the required ops.
 */
import { buildTopLevelPayload, buildChildPayload, belongsToFk, opAvailable } from '../_shared.js';
export const RULE_ID = 'cascade-integrity';
export const cascadeIntegrity = (spec) => {
    const cases = [];
    const byName = new Map(spec.models.map(m => [m.name, m]));
    for (const parent of spec.models) {
        const marker = `sc-cascade-${parent.name}`;
        const parentPayload = buildTopLevelPayload(parent, marker);
        if (!parentPayload)
            continue; // parent must be top-level seedable
        if (!opAvailable(spec, parent.name, 'delete'))
            continue;
        for (const rel of parent.relationships || []) {
            if (!/hasMany/i.test(String(rel.type || '')))
                continue;
            if (!rel.cascade)
                continue;
            const child = rel.target ? byName.get(rel.target) : undefined;
            if (!child)
                continue;
            // Single belongsTo back to this parent → seedable from the parent's id.
            const childBelongsTo = (child.relationships || []).filter(r => /belongsTo/i.test(String(r.type || '')));
            if (childBelongsTo.length !== 1)
                continue;
            if (childBelongsTo[0].target !== parent.name)
                continue;
            if (!opAvailable(spec, child.name, 'create'))
                continue;
            if (!opAvailable(spec, child.name, 'retrieve'))
                continue;
            const fk = belongsToFk(childBelongsTo[0].name);
            const childPayload = buildChildPayload(child, marker, { [fk]: '$expr:p.id' });
            const steps = [
                { op: 'create', model: parent.name, payload: parentPayload, bindAs: 'p', expect: { kind: 'ok' } },
                { op: 'create', model: child.name, payload: childPayload, bindAs: 'c', expect: { kind: 'ok' } },
                { op: 'delete', model: parent.name, idExpr: 'p.id', expect: { kind: 'ok' } },
                { op: 'retrieve', model: child.name, idExpr: 'c.id', expect: { kind: 'rejected' } },
            ];
            cases.push({
                ruleId: RULE_ID,
                specElement: `${parent.name}.${rel.name}`,
                name: `[${RULE_ID}] deleting ${parent.name} cascade-deletes its ${child.name} children`,
                steps,
            });
        }
    }
    return cases;
};
//# sourceMappingURL=cascade-integrity.js.map