/**
 * Property-Based Test: Profile panel displays all required fields
 *
 * Feature: user-profile, Property 1: Profile panel displays all required fields
 * **Validates: Requirements 1.2**
 *
 * For any valid profile object with arbitrary username, email, group, created_at,
 * and last_login values, rendering UserProfilePanel displays all five values
 * in the output.
 */
import React from 'react';
import { render, waitFor } from '@testing-library/react';
import fc from 'fast-check';
import UserProfilePanel from '../components/UserProfilePanel';

// Replicate the component's formatting logic so we know what to expect in the DOM
function formatGroupName(group) {
  if (!group) return '';
  return group.replace(/_/g, ' ');
}

function formatDate(dateStr) {
  if (!dateStr) return 'Never';
  try {
    const date = new Date(dateStr);
    if (isNaN(date.getTime())) return 'Unknown';
    return date.toLocaleDateString('en-US', {
      month: 'short',
      day: 'numeric',
      year: 'numeric',
    }) + ' at ' + date.toLocaleTimeString('en-US', {
      hour: 'numeric',
      minute: '2-digit',
      hour12: true,
    });
  } catch {
    return 'Unknown';
  }
}

// Generate ISO date strings from integer timestamps to avoid invalid Date issues
const MIN_TS = new Date('2020-01-01T00:00:00Z').getTime();
const MAX_TS = new Date('2030-12-31T23:59:59Z').getTime();
const isoDateArbitrary = fc
  .integer({ min: MIN_TS, max: MAX_TS })
  .map(ts => new Date(ts).toISOString());

// Arbitrary that generates valid profile objects.
// Use minLength >= 3 for username to avoid single-character strings that
// match substrings in other UI text (e.g., "d" appearing in "Password").
// Use a custom email generator with a longer local part for the same reason.
const profileArbitrary = fc.record({
  id: fc.integer({ min: 1, max: 100000 }),
  username: fc.stringMatching(/^[a-zA-Z][a-zA-Z0-9_]{2,19}$/),
  email: fc.tuple(
    fc.stringMatching(/^[a-z]{4,10}$/),
    fc.stringMatching(/^[a-z]{3,8}$/),
    fc.constantFrom('com', 'org', 'net', 'io')
  ).map(([local, domain, tld]) => `${local}@${domain}.${tld}`),
  group: fc.constantFrom('Admin', 'Standard_User', 'Leadership', 'Read_Only'),
  created_at: isoDateArbitrary,
  last_login: isoDateArbitrary,
});

/**
 * Helper: find all fieldValue spans in the rendered component.
 * The component renders each profile field in a fieldRow div containing
 * a fieldLabel span and a fieldValue span. We query by the known label
 * text to locate the corresponding value span.
 */
function getFieldValueByLabel(container, labelText) {
  // Each field row has structure:
  //   <div style={fieldRow}>
  //     <svg ... />
  //     <div style={fieldContent}>
  //       <span style={fieldLabel}>LABEL</span>
  //       <span style={fieldValue}>VALUE</span>
  //     </div>
  //   </div>
  const labels = container.querySelectorAll('span');
  for (const label of labels) {
    if (label.textContent.trim().toLowerCase() === labelText.toLowerCase()) {
      // The value span is the next sibling of the label span
      const valueSibling = label.nextElementSibling;
      if (valueSibling) {
        return valueSibling.textContent;
      }
    }
  }
  return null;
}

beforeEach(() => {
  process.env.REACT_APP_API_BASE = 'http://localhost:3001/api';
});

afterEach(() => {
  jest.restoreAllMocks();
});

it('Property 1: Profile panel displays all required fields for any valid profile', async () => {
  await fc.assert(
    fc.asyncProperty(profileArbitrary, async (profile) => {
      // Mock fetch to return the generated profile
      global.fetch = jest.fn().mockResolvedValue({
        ok: true,
        json: async () => ({ ...profile }),
      });

      const onClose = jest.fn();
      const { container, unmount } = render(
        <UserProfilePanel isOpen={true} onClose={onClose} />
      );

      try {
        // Wait for the profile data to be fetched and rendered.
        // Check for the username label to confirm the profile section loaded.
        await waitFor(() => {
          expect(getFieldValueByLabel(container, 'Username')).not.toBeNull();
        }, { timeout: 3000 });

        // Assert all five field values appear in their respective field rows

        // 1. Username — rendered directly in the Username field value span
        const usernameValue = getFieldValueByLabel(container, 'Username');
        expect(usernameValue).toBe(profile.username);

        // 2. Email — rendered directly in the Email field value span
        const emailValue = getFieldValueByLabel(container, 'Email');
        expect(emailValue).toBe(profile.email);

        // 3. Group — rendered through formatGroupName in the Group field value span
        const groupValue = getFieldValueByLabel(container, 'Group');
        const expectedGroup = formatGroupName(profile.group);
        expect(groupValue).toContain(expectedGroup);

        // 4. Created at — rendered through formatDate in the Account Created field value span
        const createdAtValue = getFieldValueByLabel(container, 'Account Created');
        const expectedCreatedAt = formatDate(profile.created_at);
        expect(createdAtValue).toBe(expectedCreatedAt);

        // 5. Last login — rendered through formatDate in the Last Login field value span
        const lastLoginValue = getFieldValueByLabel(container, 'Last Login');
        const expectedLastLogin = formatDate(profile.last_login);
        expect(lastLoginValue).toBe(expectedLastLogin);
      } finally {
        // Clean up to avoid leaking state between iterations
        unmount();
      }
    }),
    { numRuns: 100 }
  );
}, 120000);
