import React from 'react';
import { render, screen } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import '@testing-library/jest-dom';
import { describe, test, expect, vi } from 'vitest';
import Button from './Button.js';

describe('Button Component', () => {
  describe('Basic Rendering', () => {
    test('renders with text children', () => {
      render(<Button>Click me</Button>);

      const button = screen.getByRole('button', { name: /click me/i });
      expect(button).toBeInTheDocument();
      expect(button).toHaveAttribute('type', 'button');
    });

    test('renders with React element children', () => {
      const Component = () => <div>test</div>;

      render(
        <Button>
          <Component />
        </Button>,
      );

      const button = screen.getByRole('button');
      expect(button).toBeInTheDocument();
      expect(screen.getByText('test')).toBeInTheDocument();
    });

    test('handles empty string children', () => {
      render(<Button>{''}</Button>);

      const button = screen.getByRole('button');
      expect(button).toBeInTheDocument();
      expect(button).toHaveTextContent('');
    });

    test('has correct default attributes', () => {
      render(<Button>Test</Button>);

      const button = screen.getByRole('button');
      expect(button).toHaveAttribute('type', 'button');
      expect(button).not.toBeDisabled();
    });

    test('works in forms', async () => {
      const user = userEvent.setup();
      const handleSubmit = vi.fn((e) => e.preventDefault());

      render(
        <form onSubmit={handleSubmit}>
          <Button type="submit">Submit</Button>
        </form>,
      );

      const submitButton = screen.getByRole('button');
      expect(submitButton).toHaveAttribute('type', 'submit');
      await user.click(submitButton);

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

  describe('CSS Classes and Styling', () => {
    test('applies base CSS class', () => {
      render(<Button>Test</Button>);

      const button = screen.getByRole('button');
      expect(button).toHaveClass('conductor-button');
    });
  });

  describe('Disabled State', () => {
    test('is enabled by default', () => {
      render(<Button>Default</Button>);

      const button = screen.getByRole('button');
      expect(button).not.toBeDisabled();
      expect(button).toBeEnabled();
    });

    test('can be disabled', () => {
      render(<Button disabled={true}>Disabled</Button>);

      const button = screen.getByRole('button');
      expect(button).toBeDisabled();
    });

    test('can be explicitly enabled', () => {
      render(<Button disabled={false}>Enabled</Button>);

      const button = screen.getByRole('button');
      expect(button).not.toBeDisabled();
      expect(button).toBeEnabled();
    });
  });

  describe('Click Interactions', () => {
    test('calls onClick when button is clicked', async () => {
      const user = userEvent.setup();
      const handleClick = vi.fn();

      render(<Button onClick={handleClick}>Click me</Button>);

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

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

    test('does not call onClick when disabled', async () => {
      const user = userEvent.setup();
      const handleClick = vi.fn();

      render(
        <Button onClick={handleClick} disabled={true}>
          Disabled
        </Button>,
      );

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

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

    test('works without onClick prop (default empty function)', async () => {
      const user = userEvent.setup();

      render(<Button>No onClick</Button>);

      const button = screen.getByRole('button');
      // This should not throw an error
      await user.click(button);

      expect(button).toBeInTheDocument();
    });

    test('handles multiple clicks', async () => {
      const user = userEvent.setup();
      const handleClick = vi.fn();

      render(<Button onClick={handleClick}>Multi-click</Button>);

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

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

  describe('Keyboard Interactions', () => {
    test('responds to Enter key', async () => {
      const user = userEvent.setup();
      const handleClick = vi.fn();

      render(<Button onClick={handleClick}>Enter test</Button>);

      const button = screen.getByRole('button');
      button.focus();
      await user.keyboard('{Enter}');

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

    test('responds to Space key', async () => {
      const user = userEvent.setup();
      const handleClick = vi.fn();

      render(<Button onClick={handleClick}>Space test</Button>);

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

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

    test('does not respond to keyboard when disabled', async () => {
      const user = userEvent.setup();
      const handleClick = vi.fn();

      render(
        <Button onClick={handleClick} disabled={true}>
          Disabled
        </Button>,
      );

      const button = screen.getByRole('button');
      button.focus();
      await user.keyboard('{Enter}');
      await user.keyboard(' ');

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

  describe('Accessibility', () => {
    test('is focusable when enabled', () => {
      render(<Button>Focusable</Button>);

      const button = screen.getByRole('button');
      button.focus();
      expect(button).toHaveFocus();
    });

    test('is not focusable when disabled', () => {
      render(<Button disabled={true}>Not focusable</Button>);

      const button = screen.getByRole('button');
      expect(button).toBeDisabled();
      // Disabled buttons should not be focusable
      button.focus();
      expect(button).not.toHaveFocus();
    });

    test('supports custom aria attributes', () => {
      render(
        <Button aria-label="Custom label" aria-describedby="help-text">
          Button
        </Button>,
      );

      const button = screen.getByRole('button', { name: /custom label/i });
      expect(button).toHaveAttribute('aria-describedby', 'help-text');
    });
  });

  describe('Display Prop', () => {
    test('accepts variant display value', () => {
      render(<Button variant="surface">Secondary Button</Button>);
      const button = screen.getByRole('button');
      expect(button).toHaveClass('conductor-button--surface');
    });

    test('default variant is solid', () => {
      render(<Button>Button</Button>);
      const button = screen.getByRole('button');
      expect(button).toHaveClass('conductor-button--solid');
    });

    test('accepts size display value', () => {
      render(<Button size="1">Button</Button>);
      const button = screen.getByRole('button');
      expect(button).toHaveClass('conductor-button--size-1');
    });

    test('Default size is 2', () => {
      render(<Button>Button</Button>);
      const button = screen.getByRole('button');
      expect(button).toHaveClass('conductor-button--size-2');
    });
  });
});
