/**
 * Property-Based Test: Mismatched password confirmation is rejected client-side
 *
 * Feature: user-profile, Property 5: Mismatched password confirmation is rejected client-side
 * **Validates: Requirements 2.4**
 *
 * For any two distinct strings used as newPassword and confirmPassword in the
 * Password_Change_Form, the form displays a validation error and does not
 * submit a request to the Auth_API.
 */
import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import fc from 'fast-check';
import UserProfilePanel from '../components/UserProfilePanel';

// Mock profile returned by the API so the form renders
const MOCK_PROFILE = {
  id: 1,
  username: 'testuser',
  email: 'test@example.com',
  group: 'Standard_User',
  created_at: '2026-01-15T10:30:00Z',
  last_login: '2026-07-20T14:22:00Z',
};

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

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

it('Property 5: Mismatched password confirmation is rejected client-side', async () => {
  // Arbitrary: generate a newPassword of at least 8 characters and a distinct confirmPassword
  // (also non-empty so the validation message renders).
  const mismatchedPairArbitrary = fc
    .tuple(
      fc.string({ minLength: 8, maxLength: 40 }).filter(s => s.trim().length >= 8),
      fc.string({ minLength: 1, maxLength: 40 })
    )
    .filter(([newPw, confirmPw]) => newPw !== confirmPw);

  await fc.assert(
    fc.asyncProperty(mismatchedPairArbitrary, async ([newPassword, confirmPassword]) => {
      // Mock fetch: first call returns the profile, subsequent calls are tracked
      const fetchMock = jest.fn().mockImplementation((url) => {
        if (typeof url === 'string' && url.includes('/auth/profile')) {
          return Promise.resolve({
            ok: true,
            json: async () => ({ ...MOCK_PROFILE }),
          });
        }
        // Any other call (e.g. change-password) — should NOT happen
        return Promise.resolve({
          ok: true,
          json: async () => ({ message: 'Password changed successfully' }),
        });
      });
      global.fetch = fetchMock;

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

      try {
        // Wait for the profile to load
        await waitFor(() => {
          expect(container.textContent).toContain(MOCK_PROFILE.username);
        }, { timeout: 3000 });

        // Fill in the form fields
        const currentPwInput = getByPlaceholderText('Enter current password');
        const newPwInput = getByPlaceholderText('Minimum 8 characters');
        const confirmPwInput = getByPlaceholderText('Re-enter new password');

        fireEvent.change(currentPwInput, { target: { value: 'currentpass1' } });
        fireEvent.change(newPwInput, { target: { value: newPassword } });
        fireEvent.change(confirmPwInput, { target: { value: confirmPassword } });

        // Assert the "Passwords do not match" validation error is displayed
        expect(container.textContent).toContain('Passwords do not match');

        // Assert the submit button is disabled
        const submitButton = container.querySelector('button[type="submit"]');
        expect(submitButton).not.toBeNull();
        expect(submitButton.disabled).toBe(true);

        // Assert that no call was made to the change-password endpoint
        const changePasswordCalls = fetchMock.mock.calls.filter(
          ([url]) => typeof url === 'string' && url.includes('/auth/change-password')
        );
        expect(changePasswordCalls).toHaveLength(0);
      } finally {
        unmount();
      }
    }),
    { numRuns: 100 }
  );
}, 120000);
