import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { AuthInput } from './AuthInput';
import { AuthButton } from './AuthButton';
import { AuthFormField } from './AuthFormField';
import { AuthErrorMessage } from './AuthErrorMessage';

describe('AuthInput', () => {
  it('should render input with label', () => {
    render(<AuthInput label="Email" id="email-input" />);
    expect(screen.getByLabelText('Email')).toBeInTheDocument();
  });

  it('should display error message when error prop is provided', () => {
    render(<AuthInput error="Invalid email" id="email-input" />);
    expect(screen.getByText('Invalid email')).toBeInTheDocument();
    expect(screen.getByRole('alert')).toBeInTheDocument();
  });

  it('should have aria-invalid when error is present', () => {
    render(<AuthInput error="Error message" id="email-input" />);
    const input = screen.getByRole('textbox');
    expect(input).toHaveAttribute('aria-invalid', 'true');
  });

  it('should apply error styles when error is present', () => {
    render(<AuthInput error="Error" id="email-input" />);
    const input = screen.getByRole('textbox');
    expect(input.className).toContain('border-red-500');
  });

  it('should handle user input', async () => {
    const user = userEvent.setup();
    const handleChange = vi.fn();
    render(
      <AuthInput
        label="Email"
        id="email-input"
        onChange={handleChange}
        type="email"
      />,
    );

    const input = screen.getByLabelText('Email');
    await user.type(input, 'test@example.com');

    expect(handleChange).toHaveBeenCalled();
    expect(input).toHaveValue('test@example.com');
  });

  it('should support all standard input props', () => {
    render(
      <AuthInput
        label="Password"
        id="password-input"
        type="password"
        placeholder="Enter password"
        required
      />,
    );

    const input = screen.getByLabelText('Password');
    expect(input).toHaveAttribute('type', 'password');
    expect(input).toHaveAttribute('placeholder', 'Enter password');
    expect(input).toBeRequired();
  });
});

describe('AuthButton', () => {
  it('should render button with children', () => {
    render(<AuthButton>Submit</AuthButton>);
    expect(screen.getByRole('button', { name: 'Submit' })).toBeInTheDocument();
  });

  it('should show loading state', () => {
    render(<AuthButton loading>Submit</AuthButton>);
    expect(screen.getByText('Chargement...')).toBeInTheDocument();
    expect(screen.getByRole('button')).toBeDisabled();
    expect(screen.getByRole('button')).toHaveAttribute('aria-busy', 'true');
  });

  it('should be disabled when loading', () => {
    render(<AuthButton loading>Submit</AuthButton>);
    expect(screen.getByRole('button')).toBeDisabled();
  });

  it('should be disabled when disabled prop is true', () => {
    render(<AuthButton disabled>Submit</AuthButton>);
    expect(screen.getByRole('button')).toBeDisabled();
  });

  it('should apply primary variant styles by default', () => {
    render(<AuthButton>Submit</AuthButton>);
    const button = screen.getByRole('button');
    expect(button.className).toContain('bg-blue-600');
  });

  it('should apply secondary variant styles', () => {
    render(<AuthButton variant="secondary">Cancel</AuthButton>);
    const button = screen.getByRole('button');
    expect(button.className).toContain('bg-gray-200');
  });

  it('should handle click events', async () => {
    const user = userEvent.setup();
    const handleClick = vi.fn();
    render(<AuthButton onClick={handleClick}>Click me</AuthButton>);

    const button = screen.getByRole('button');
    await user.click(button);

    expect(handleClick).toHaveBeenCalledTimes(1);
  });

  it('should not trigger click when disabled', async () => {
    const user = userEvent.setup();
    const handleClick = vi.fn();
    render(
      <AuthButton disabled onClick={handleClick}>
        Click me
      </AuthButton>,
    );

    const button = screen.getByRole('button');
    await user.click(button);

    expect(handleClick).not.toHaveBeenCalled();
  });
});

describe('AuthFormField', () => {
  it('should render label and children', () => {
    render(
      <AuthFormField label="Email">
        <input type="email" />
      </AuthFormField>,
    );
    expect(screen.getByText('Email')).toBeInTheDocument();
  });

  it('should show required indicator', () => {
    render(
      <AuthFormField label="Email" required>
        <input type="email" />
      </AuthFormField>,
    );
    const label = screen.getByText('Email');
    expect(label.textContent).toContain('*');
  });

  it('should display error message', () => {
    render(
      <AuthFormField label="Email" error="Invalid email">
        <input type="email" />
      </AuthFormField>,
    );
    expect(screen.getByText('Invalid email')).toBeInTheDocument();
    expect(screen.getByRole('alert')).toBeInTheDocument();
  });

  it('should display help text when no error', () => {
    render(
      <AuthFormField label="Email" helpText="Enter your email address">
        <input type="email" />
      </AuthFormField>,
    );
    expect(screen.getByText('Enter your email address')).toBeInTheDocument();
  });

  it('should not display help text when error is present', () => {
    render(
      <AuthFormField
        label="Email"
        error="Invalid email"
        helpText="Enter your email address"
      >
        <input type="email" />
      </AuthFormField>,
    );
    expect(screen.getByText('Invalid email')).toBeInTheDocument();
    expect(
      screen.queryByText('Enter your email address'),
    ).not.toBeInTheDocument();
  });
});

describe('AuthErrorMessage', () => {
  it('should render error message', () => {
    render(<AuthErrorMessage message="An error occurred" />);
    expect(screen.getByText('An error occurred')).toBeInTheDocument();
    expect(screen.getByRole('alert')).toBeInTheDocument();
  });

  it('should not render when message is empty', () => {
    const { container } = render(<AuthErrorMessage message="" />);
    expect(container.firstChild).toBeNull();
  });

  it('should have aria-live attribute', () => {
    render(<AuthErrorMessage message="Error" />);
    const alert = screen.getByRole('alert');
    expect(alert).toHaveAttribute('aria-live', 'polite');
  });

  it('should apply custom className', () => {
    render(<AuthErrorMessage message="Error" className="custom-class" />);
    const alert = screen.getByRole('alert');
    expect(alert.className).toContain('custom-class');
  });

  it('should support custom id', () => {
    render(<AuthErrorMessage message="Error" id="custom-error-id" />);
    const alert = screen.getByRole('alert');
    expect(alert).toHaveAttribute('id', 'custom-error-id');
  });
});
