/**
 * Property-Based Test: Remediate Queue Grouping
 *
 * Feature: ivanti-queue-remediation
 * Property 2: Remediate items grouped into vendor sections, never Inventory
 *
 * For any queue item with workflow_type "Remediate", the groupQueueItems function
 * SHALL place it in a vendor-grouped section (using the item's vendor field, or
 * "Unknown" if vendor is empty/null) and SHALL NOT place it in the Inventory section.
 *
 * **Validates: Requirements 2.1, 2.2, 2.4**
 */
import fc from 'fast-check';
import { groupQueueItems } from '../utils/queueGrouping';

// ---------------------------------------------------------------------------
// Arbitraries
// ---------------------------------------------------------------------------

const arbVendor = fc.oneof(
    fc.string({ minLength: 1, maxLength: 100 }).filter(s => s.trim().length > 0),
    fc.constantFrom('Microsoft', 'Cisco', 'Juniper', 'ADTRAN', 'VMware')
);

const arbEmptyVendor = fc.oneof(
    fc.constant(''),
    fc.constant(null),
    fc.constant(undefined),
    fc.constant('   ') // whitespace only
);

const arbRemediateItemWithVendor = fc.record({
    id: fc.integer({ min: 1, max: 100000 }),
    workflow_type: fc.constant('Remediate'),
    vendor: arbVendor,
    status: fc.constant('pending'),
    finding_id: fc.string({ minLength: 1, maxLength: 20 }),
    finding_title: fc.string({ minLength: 1, maxLength: 100 }),
});

const arbRemediateItemNoVendor = fc.record({
    id: fc.integer({ min: 1, max: 100000 }),
    workflow_type: fc.constant('Remediate'),
    vendor: arbEmptyVendor,
    status: fc.constant('pending'),
    finding_id: fc.string({ minLength: 1, maxLength: 20 }),
    finding_title: fc.string({ minLength: 1, maxLength: 100 }),
});

const arbInventoryItem = fc.record({
    id: fc.integer({ min: 100001, max: 200000 }),
    workflow_type: fc.constantFrom('CARD', 'GRANITE', 'DECOM'),
    vendor: fc.constant(''),
    status: fc.constant('pending'),
    finding_id: fc.string({ minLength: 1, maxLength: 20 }),
    finding_title: fc.string({ minLength: 1, maxLength: 100 }),
});

// ---------------------------------------------------------------------------
// Property 2: Remediate items grouped into vendor sections, never Inventory
// ---------------------------------------------------------------------------
describe('Feature: ivanti-queue-remediation, Property 2: Remediate items grouped into vendor sections, never Inventory', () => {
    it('Remediate items with a vendor are placed in vendor-grouped sections, never Inventory', () => {
        fc.assert(
            fc.property(
                fc.array(arbRemediateItemWithVendor, { minLength: 1, maxLength: 20 })
                    .map(items => {
                        // Ensure unique IDs
                        const seen = new Set();
                        return items.filter(item => {
                            if (seen.has(item.id)) return false;
                            seen.add(item.id);
                            return true;
                        });
                    })
                    .filter(items => items.length > 0),
                (items) => {
                    const sections = groupQueueItems(items);

                    // No Inventory section should exist (Remediate items never go there)
                    const inventorySection = sections.find(s => s.type === 'inventory');
                    expect(inventorySection).toBeUndefined();

                    // All items should be in vendor sections
                    const vendorSections = sections.filter(s => s.type === 'vendor');
                    const allGroupedItems = vendorSections.flatMap(s => s.items);
                    expect(allGroupedItems.length).toBe(items.length);

                    // Each item should be in its vendor's section
                    for (const item of items) {
                        const expectedVendor = item.vendor?.trim() || 'Unknown';
                        const section = vendorSections.find(s => s.label === expectedVendor);
                        expect(section).toBeDefined();
                        expect(section.items.some(i => i.id === item.id)).toBe(true);
                    }
                }
            ),
            { numRuns: 100 }
        );
    });

    it('Remediate items with empty/null/whitespace-only vendor land in "Unknown" section', () => {
        fc.assert(
            fc.property(
                fc.array(arbRemediateItemNoVendor, { minLength: 1, maxLength: 10 })
                    .map(items => {
                        const seen = new Set();
                        return items.filter(item => {
                            if (seen.has(item.id)) return false;
                            seen.add(item.id);
                            return true;
                        });
                    })
                    .filter(items => items.length > 0),
                (items) => {
                    const sections = groupQueueItems(items);

                    // No Inventory section
                    const inventorySection = sections.find(s => s.type === 'inventory');
                    expect(inventorySection).toBeUndefined();

                    // All items should be in the "Unknown" vendor section
                    const unknownSection = sections.find(s => s.label === 'Unknown');
                    expect(unknownSection).toBeDefined();
                    expect(unknownSection.items.length).toBe(items.length);
                }
            ),
            { numRuns: 100 }
        );
    });

    it('Remediate items are never placed in the Inventory section even when mixed with inventory items', () => {
        fc.assert(
            fc.property(
                fc.array(arbRemediateItemWithVendor, { minLength: 1, maxLength: 10 })
                    .map(items => {
                        const seen = new Set();
                        return items.filter(item => {
                            if (seen.has(item.id)) return false;
                            seen.add(item.id);
                            return true;
                        });
                    })
                    .filter(items => items.length > 0),
                fc.array(arbInventoryItem, { minLength: 1, maxLength: 5 })
                    .map(items => {
                        const seen = new Set();
                        return items.filter(item => {
                            if (seen.has(item.id)) return false;
                            seen.add(item.id);
                            return true;
                        });
                    })
                    .filter(items => items.length > 0),
                (remediateItems, inventoryItems) => {
                    const allItems = [...remediateItems, ...inventoryItems];
                    const sections = groupQueueItems(allItems);

                    // Inventory section exists (from inventory items)
                    const inventorySection = sections.find(s => s.type === 'inventory');
                    expect(inventorySection).toBeDefined();

                    // No Remediate items in the inventory section
                    const remediateInInventory = inventorySection.items.filter(
                        i => i.workflow_type === 'Remediate'
                    );
                    expect(remediateInInventory.length).toBe(0);

                    // All Remediate items are in vendor sections
                    const vendorSections = sections.filter(s => s.type === 'vendor');
                    const allVendorItems = vendorSections.flatMap(s => s.items);
                    for (const item of remediateItems) {
                        expect(allVendorItems.some(i => i.id === item.id)).toBe(true);
                    }
                }
            ),
            { numRuns: 100 }
        );
    });
});
