/**
 * Property-Based Test: Empty Section Omission
 *
 * Feature: queue-collapsible-sections, Property 3: Empty Section Omission
 * **Validates: Requirements 1.6, 1.7**
 *
 * For any array of queue items (including empty arrays), the grouped output
 * contains no sections with zero items. If no CARD/GRANITE/DECOM items exist
 * in the input, no section with type 'inventory' appears in the output.
 */
import fc from 'fast-check';

// Inline the grouping logic since the utility file may not exist yet
function groupQueueItems(visibleItems) {
  const INVENTORY_TYPES = new Set(['CARD', 'GRANITE', 'DECOM']);
  const inventoryItems = [];
  const vendorMap = new Map();
  for (const item of visibleItems) {
    if (INVENTORY_TYPES.has(item.workflow_type)) {
      inventoryItems.push(item);
    } else {
      const vendor = item.vendor?.trim() || 'Unknown';
      if (!vendorMap.has(vendor)) vendorMap.set(vendor, []);
      vendorMap.get(vendor).push(item);
    }
  }
  const sections = [];
  if (inventoryItems.length > 0) {
    sections.push({ key: 'inventory', label: 'Inventory', type: 'inventory', items: inventoryItems });
  }
  const sortedVendors = [...vendorMap.entries()].sort((a, b) => a[0].localeCompare(b[0]));
  for (const [vendor, items] of sortedVendors) {
    sections.push({ key: `vendor:${vendor}`, label: vendor, type: 'vendor', items });
  }
  return sections;
}

// Generator for queue items with various workflow types and vendors
const workflowTypeArb = fc.constantFrom('CARD', 'GRANITE', 'DECOM', 'FP', 'Archer');
const vendorArb = fc.oneof(
  fc.constant(null),
  fc.constant(undefined),
  fc.constant(''),
  fc.constant('  '),
  fc.stringMatching(/^[A-Za-z][A-Za-z0-9 ]{0,14}$/)
);

const queueItemArb = fc.record({
  id: fc.integer({ min: 1, max: 100000 }),
  workflow_type: workflowTypeArb,
  vendor: vendorArb,
  hostname: fc.stringMatching(/^[a-z]{3,10}$/),
  status: fc.constant('pending'),
});

const queueItemsArb = fc.array(queueItemArb, { minLength: 0, maxLength: 50 });

describe('Queue Grouping — Property 3: Empty Section Omission', () => {
  it('no section in the output has zero items', () => {
    fc.assert(
      fc.property(queueItemsArb, (items) => {
        const sections = groupQueueItems(items);
        for (const section of sections) {
          expect(section.items.length).toBeGreaterThan(0);
        }
      }),
      { numRuns: 200 }
    );
  });

  it('if no inventory-type items exist, no inventory section appears', () => {
    // Generate arrays that explicitly exclude inventory types
    const nonInventoryTypeArb = fc.constantFrom('FP', 'Archer');
    const nonInventoryItemArb = fc.record({
      id: fc.integer({ min: 1, max: 100000 }),
      workflow_type: nonInventoryTypeArb,
      vendor: vendorArb,
      hostname: fc.stringMatching(/^[a-z]{3,10}$/),
      status: fc.constant('pending'),
    });
    const nonInventoryItemsArb = fc.array(nonInventoryItemArb, { minLength: 0, maxLength: 50 });

    fc.assert(
      fc.property(nonInventoryItemsArb, (items) => {
        const sections = groupQueueItems(items);
        const inventorySection = sections.find(s => s.type === 'inventory');
        expect(inventorySection).toBeUndefined();
      }),
      { numRuns: 200 }
    );
  });

  it('if no CARD/GRANITE/DECOM items exist in a mixed array, no inventory section appears', () => {
    fc.assert(
      fc.property(queueItemsArb, (items) => {
        const INVENTORY_TYPES = new Set(['CARD', 'GRANITE', 'DECOM']);
        const hasInventoryItems = items.some(item => INVENTORY_TYPES.has(item.workflow_type));
        const sections = groupQueueItems(items);
        const inventorySection = sections.find(s => s.type === 'inventory');

        if (!hasInventoryItems) {
          expect(inventorySection).toBeUndefined();
        } else {
          expect(inventorySection).toBeDefined();
          expect(inventorySection.items.length).toBeGreaterThan(0);
        }
      }),
      { numRuns: 200 }
    );
  });
});
