// Feature: snowui-dashboard-redesign, Property 1: Navigation section grouping is complete and correct
// **Validates: Requirements 1.2**

import { describe, it, expect } from 'vitest';
import * as fc from 'fast-check';
import {
  groupNavItemsBySection,
  type NavItem,
  type NavSection,
  type IconName,
  type UserRole,
} from '@/lib/constants/navigation';

const ALL_ROLES: readonly UserRole[] = ['Super_Admin', 'Publisher_Admin', 'Viewer'] as const;
const SECTIONS: NavSection[] = ['favorites', 'dashboards', 'pages', 'analytics'];
const ICONS: IconName[] = [
  'overview', 'works', 'composers', 'payees', 'contracts',
  'income', 'transactions', 'costs', 'statements', 'suspense', 'audit', 'settings',
];

/**
 * Arbitrary that generates a valid NavItem with a random section assignment.
 */
const navItemArb: fc.Arbitrary<NavItem> = fc.record({
  label: fc.string({ minLength: 1, maxLength: 20 }),
  href: fc.string({ minLength: 1, maxLength: 30 }).map((s) => `/${s.replace(/\//g, '')}`),
  icon: fc.constantFrom(...ICONS),
  roles: fc.constant(ALL_ROLES),
  section: fc.constantFrom<NavSection>(...SECTIONS),
});

/**
 * Arbitrary that generates a NavItem without a section (should default to 'pages').
 */
const navItemNoSectionArb: fc.Arbitrary<NavItem> = fc.record({
  label: fc.string({ minLength: 1, maxLength: 20 }),
  href: fc.string({ minLength: 1, maxLength: 30 }).map((s) => `/${s.replace(/\//g, '')}`),
  icon: fc.constantFrom(...ICONS),
  roles: fc.constant(ALL_ROLES),
});

describe('Property 1: Navigation section grouping is complete and correct', () => {
  it('groupNavItemsBySection places each item in the correct section with no items lost or duplicated', () => {
    fc.assert(
      fc.property(
        fc.array(navItemArb, { minLength: 0, maxLength: 20 }),
        (items) => {
          const grouped = groupNavItemsBySection(items);

          // Collect all items from all groups
          const allGroupedItems: NavItem[] = [
            ...grouped.favorites,
            ...grouped.dashboards,
            ...grouped.pages,
            ...grouped.analytics,
          ];

          // No items lost: total count matches
          expect(allGroupedItems).toHaveLength(items.length);

          // Each item is in the correct section
          for (const item of items) {
            const expectedSection = item.section ?? 'pages';
            expect(grouped[expectedSection]).toContainEqual(item);
          }

          // No items duplicated: each group only contains items assigned to it
          for (const section of SECTIONS) {
            for (const item of grouped[section]) {
              const itemSection = item.section ?? 'pages';
              expect(itemSection).toBe(section);
            }
          }
        },
      ),
      { numRuns: 100 },
    );
  });

  it('items without a section field default to pages', () => {
    fc.assert(
      fc.property(
        fc.array(navItemNoSectionArb, { minLength: 1, maxLength: 10 }),
        (items) => {
          const grouped = groupNavItemsBySection(items);

          // All items without section should be in 'pages'
          expect(grouped.pages).toHaveLength(items.length);
          expect(grouped.favorites).toHaveLength(0);
          expect(grouped.dashboards).toHaveLength(0);
          expect(grouped.analytics).toHaveLength(0);
        },
      ),
      { numRuns: 100 },
    );
  });
});
