import { describe, test, expect, vi } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import { AppStateProvider } from '../Context.js';
import Keywords from './Keywords.js';

describe('Keywords Component', () => {
  test('Generate content guidance button disabled until at least 1 keyword has been entered', async () => {
    const user = userEvent.setup();
    render(
      <AppStateProvider initialState={{ accountId: '12345' }}>
        <Keywords />
      </AppStateProvider>,
    );

    const generateButton = screen.getByRole('button', { name: /generate content guidance/i });

    // Initially disabled when no keywords
    expect(generateButton).toBeDisabled();

    // Enter a keyword
    const input = screen.getByRole('textbox');
    await user.type(input, 'test-tag{Enter}');

    expect(generateButton).not.toBeDisabled();
  });

  test('Navigate to the next tab when Generate content guidance button is clicked', async () => {
    const mockSetTab = vi.fn();
    const user = userEvent.setup();
    render(
      <AppStateProvider initialState={{ accountId: '12345' }}>
        <Keywords setTab={mockSetTab} nextTab={2} />
      </AppStateProvider>,
    );

    const generateButton = screen.getByRole('button', { name: /generate content guidance/i });

    // Add a keyword to enable the button
    const input = screen.getByRole('textbox');
    await user.type(input, 'test-tag{Enter}');

    expect(generateButton).not.toBeDisabled();

    // Click the Generate content guidance button
    await user.click(generateButton);

    // Should call setTab with nextTab (1)
    expect(mockSetTab).toHaveBeenCalledTimes(1);
    expect(mockSetTab).toHaveBeenCalledWith(2);
  });

  test('Loading spinner shows when Evaluate button is clicked', async () => {
    const user = userEvent.setup();
    render(
      <AppStateProvider initialState={{ accountId: '12345' }}>
        <Keywords />
      </AppStateProvider>,
    );

    const evaluateButton = screen.getByRole('button', { name: /evaluate/i });

    // Add a keyword to enable the Evaluate button
    const input = screen.getByRole('textbox');
    await user.type(input, 'hoagie{Enter}');

    expect(evaluateButton).not.toBeDisabled();

    await user.click(evaluateButton);

    // Loading spinner should be visible
    const loadingSpinner = screen.getByRole('status');
    expect(loadingSpinner).toBeInTheDocument();
  });

  test('Error message shows on bad response', async () => {
    const user = userEvent.setup();
    render(
      <AppStateProvider initialState={{ accountId: '12345' }}>
        <Keywords />
      </AppStateProvider>,
    );

    const evaluateButton = screen.getByRole('button', { name: /evaluate/i });

    // Add a keyword to enable the Evaluate button
    let input = screen.getByRole('textbox');
    await user.type(input, 'cheese steak{Enter}');

    expect(evaluateButton).not.toBeDisabled();

    await user.click(evaluateButton);

    expect(screen.getByRole('alert')).toBeInTheDocument();

    await user.click(screen.getByLabelText('Remove cheese steak'));
    input = screen.getByRole('textbox');
    await user.type(input, 'phanatic{Enter}');

    const tryAgainButton = screen.getByRole('button', { name: /please try again/i });
    await user.click(tryAgainButton);
    await waitFor(() => {
      const spinner = screen.queryByText(/loading/i);
      expect(spinner).not.toBeInTheDocument();
    });
    await waitFor(() => {
      expect(screen.getByRole('table')).toBeInTheDocument();
    });
    const alert = screen.queryByRole('alert');
    expect(alert).not.toBeInTheDocument();
  });

  test('handle 200 response that contains an error', async () => {
    const user = userEvent.setup();
    render(
      <AppStateProvider initialState={{ accountId: '12345' }}>
        <Keywords />
      </AppStateProvider>,
    );

    const evaluateButton = screen.getByRole('button', { name: /evaluate/i });

    const input = screen.getByRole('textbox');
    await user.type(input, 'rocky{Enter}');

    expect(evaluateButton).not.toBeDisabled();

    await user.click(evaluateButton);

    expect(screen.getByRole('alert')).toBeInTheDocument();
  });
});
