/**
 * Property-Based Test: Filter state mutual exclusivity
 *
 * Feature: compliance-nonmetric-filters, Property 3: Filter state mutual exclusivity
 * **Validates: Requirements 3.4, 3.5, 5.1**
 *
 * For any prior filter state and any filter action (metric card click, chip click,
 * or clear), the resulting state is exactly one of: null, { type: 'metric', ids: [...] },
 * or { type: 'nonmetric', id: string } — never undefined, never both.
 */
import fc from 'fast-check';

// Replicate the filter state transition logic from CompliancePage
function applyFilterAction(currentState, action) {
    if (action.type === 'clear') {
        return null;
    }
    if (action.type === 'metric_click') {
        const familyIds = action.ids;
        // If currently active metric with same ids, toggle off
        if (currentState?.type === 'metric' &&
            currentState.ids.length === familyIds.length &&
            familyIds.every(id => currentState.ids.includes(id))) {
            return null;
        }
        return { type: 'metric', ids: familyIds };
    }
    if (action.type === 'chip_click') {
        const metricId = action.id;
        // If currently active nonmetric with same id, toggle off
        if (currentState?.type === 'nonmetric' && currentState.id === metricId) {
            return null;
        }
        return { type: 'nonmetric', id: metricId };
    }
    return currentState;
}

function isValidFilterState(state) {
    if (state === null) return true;
    if (state && state.type === 'metric' && Array.isArray(state.ids) && state.ids.length > 0) return true;
    if (state && state.type === 'nonmetric' && typeof state.id === 'string' && state.id.length > 0) return true;
    return false;
}

// Generators
const metricIdArb = fc.stringMatching(/^[A-Za-z0-9_.]{1,20}$/);

const filterStateArb = fc.oneof(
    fc.constant(null),
    fc.array(metricIdArb, { minLength: 1, maxLength: 5 }).map(ids => ({ type: 'metric', ids })),
    metricIdArb.map(id => ({ type: 'nonmetric', id }))
);

const filterActionArb = fc.oneof(
    fc.constant({ type: 'clear' }),
    fc.array(metricIdArb, { minLength: 1, maxLength: 5 }).map(ids => ({ type: 'metric_click', ids })),
    metricIdArb.map(id => ({ type: 'chip_click', id }))
);

describe('Compliance Non-Metric Filter — Property 3: Filter state mutual exclusivity', () => {
    it('resulting state is always exactly one of null, metric, or nonmetric — never undefined or combined', () => {
        fc.assert(
            fc.property(filterStateArb, filterActionArb, (priorState, action) => {
                const result = applyFilterAction(priorState, action);

                expect(result).not.toBeUndefined();
                expect(isValidFilterState(result)).toBe(true);

                // Never has both metric and nonmetric properties
                if (result !== null) {
                    if (result.type === 'metric') {
                        expect(result).not.toHaveProperty('id');
                    }
                    if (result.type === 'nonmetric') {
                        expect(result).not.toHaveProperty('ids');
                    }
                }
            }),
            { numRuns: 100 }
        );
    });

    it('clear action always results in null regardless of prior state', () => {
        fc.assert(
            fc.property(filterStateArb, (priorState) => {
                const result = applyFilterAction(priorState, { type: 'clear' });
                expect(result).toBeNull();
            }),
            { numRuns: 100 }
        );
    });

    it('metric click replaces any prior state with metric filter or null (toggle off)', () => {
        fc.assert(
            fc.property(filterStateArb, fc.array(metricIdArb, { minLength: 1, maxLength: 5 }), (priorState, ids) => {
                const result = applyFilterAction(priorState, { type: 'metric_click', ids });

                if (result === null) {
                    // Toggled off — prior must have been metric with same ids
                    expect(priorState?.type).toBe('metric');
                } else {
                    expect(result.type).toBe('metric');
                    expect(result.ids).toEqual(ids);
                }
            }),
            { numRuns: 100 }
        );
    });

    it('chip click replaces any prior state with nonmetric filter or null (toggle off)', () => {
        fc.assert(
            fc.property(filterStateArb, metricIdArb, (priorState, id) => {
                const result = applyFilterAction(priorState, { type: 'chip_click', id });

                if (result === null) {
                    // Toggled off — prior must have been nonmetric with same id
                    expect(priorState?.type).toBe('nonmetric');
                    expect(priorState?.id).toBe(id);
                } else {
                    expect(result.type).toBe('nonmetric');
                    expect(result.id).toBe(id);
                }
            }),
            { numRuns: 100 }
        );
    });
});
