import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import type { Mock } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { useBusy } from '../../hooks/useBusy/useBusy';
import { IconName } from '../Icons';
import { Actions } from './Actions';
import { ActionData } from './Actions.models';

vi.mock('../../initialize');
vi.mock('../../hooks/useBusy/useBusy', () => ({
  useBusy: vi.fn(() => ({ isBusy: false })),
}));

const spy1 = vi.fn();
const spy2 = vi.fn();
const spy3 = vi.fn();
const mockActions: ActionData[] = [
  { label: 'action-label', onActionSelected: spy1 },
  { label: 'action-label', onActionSelected: spy2 },
  { label: 'action-label', onActionSelected: spy3 },
];

describe('Actions', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders the component without crashing', () => {
    const { container } = render(<Actions actions={[]} />);

    expect(container).toBeTruthy();
  });

  it('renders an Action for each action', () => {
    const { container } = render(<Actions actions={mockActions} />);

    const actions = container.querySelectorAll('[data-test-id="action"]');

    expect(actions).toHaveLength(mockActions.length);
  });

  it('raises the click event', () => {
    const { container } = render(<Actions actions={mockActions} />);

    const action = container.querySelector('[data-test-id="action"]');

    if (action) {
      fireEvent.click(action);
    }

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

  it('renders Actions with the passed in width prop', () => {
    const mockWidth = '150px';
    const { container } = render(<Actions actions={[]} width={mockWidth} />);

    const actionsContainer = container.querySelector('.actions-container');

    expect(actionsContainer).toHaveStyle({ width: mockWidth });
  });

  it('displays an empty Actions container if no actions are passed in', () => {
    const { container } = render(<Actions actions={[]} />);

    const actionsContainer = container.querySelector('.actions-container');
    const actions = container.querySelectorAll('[data-test-id="action"]');

    expect(actionsContainer).toBeInTheDocument();
    expect(actions).toHaveLength(0);
  });

  it('allows the icon to be changed', () => {
    const iconProp: IconName = IconName.Delete;
    const { container } = render(
      <Actions
        actions={[
          {
            label: 'action-label',
            icon: iconProp,
            onActionSelected: () => undefined,
          },
        ]}
      />,
    );

    const action = container.querySelector('[data-test-id="action"]');

    expect(action).toBeInTheDocument();
    // Icon is rendered inside the action
    const icon = action?.querySelector('svg');
    expect(icon).toBeInTheDocument();
  });

  it('disables all actions when busy', () => {
    (useBusy as Mock).mockImplementation(() => ({ isBusy: true }));

    const { container } = render(<Actions actions={mockActions} />);

    const actions = container.querySelectorAll('[data-test-id="action"]');

    actions.forEach((action) => {
      // When disabled, the action gets the isDisabled class
      expect(action.classList.contains('isDisabled')).toBe(true);
    });
  });
});
