import {
  mockMatchMedia,
  mockResizeObserver,
  render,
  screen,
  userEvent,
  waitFor,
} from '../../test-utils';

import { CurrencySelector } from './CurrencySelector';

mockMatchMedia();
mockResizeObserver();

describe('CurrencySelector', () => {
  it('can change currency', async () => {
    const onChange = jest.fn();
    render(
      <CurrencySelector
        options={mockCurrencies}
        id="id"
        currency="USD"
        labelId="labelId"
        onChange={onChange}
      />,
    );

    await userEvent.click(screen.getByRole('combobox', { name: 'Select currency' }));

    await userEvent.click(
      screen.getByRole('option', {
        name: /aed united arab emirates dirham/iu,
      }),
    );

    expect(onChange).toHaveBeenCalledWith('AED');
  });

  it('locks the input when no onChange is provided', async () => {
    render(<CurrencySelector options={mockCurrencies} id="id" currency="USD" labelId="labelId" />);

    await userEvent.click(screen.getByRole('combobox', { name: 'Select currency' }));

    expect(screen.getByRole('combobox')).toBeDisabled();
  });

  it('enables currency selection when just one group with multiple currencies', async () => {
    render(
      <CurrencySelector
        options={[
          {
            title: 'Popular',
            currencies: [
              {
                code: 'USD',
                label: 'US Dollar',
                keywords: ['USD', 'US Dollar'],
              },
              {
                code: 'EUR',
                label: 'Euro',
                keywords: ['EUR', 'Euro'],
              },
            ],
          },
        ]}
        id="id"
        currency="USD"
        labelId="labelId"
        onChange={jest.fn()}
      />,
    );

    expect(screen.getByRole('combobox')).toBeEnabled();
  });

  it('disables currency selection when just one currency', async () => {
    render(
      <CurrencySelector
        options={[
          {
            title: 'Popular',
            currencies: [
              {
                code: 'USD',
                label: 'US Dollar',
                keywords: ['USD', 'US Dollar'],
              },
            ],
          },
        ]}
        id="id"
        currency="USD"
        labelId="labelId"
        onChange={jest.fn()}
      />,
    );

    expect(screen.getByRole('combobox')).toBeDisabled();
  });

  it('displays formatted currency code when the currency is selected', () => {
    render(<CurrencySelector options={mockCurrencies} id="id" currency="USC" labelId="labelId" />);

    expect(screen.getByRole('combobox', { name: 'Select currency' })).toHaveTextContent('USDC');
  });

  it('displays formatted currency code in the selected option content', async () => {
    render(
      <CurrencySelector
        options={[
          {
            title: 'All',
            currencies: [
              { code: 'USC', label: 'USDC', keywords: ['USDC'] },
              { code: 'EUR', label: 'Euro', keywords: ['EUR'] },
            ],
          },
        ]}
        id="id"
        currency="USC"
        labelId="labelId"
        onChange={jest.fn()}
      />,
    );

    await userEvent.click(screen.getByRole('combobox'));

    expect(screen.getByRole('option', { name: /^usdc/iu })).toHaveTextContent('USDC');
  });

  it('fires onChange with the raw currency code when selecting a formatted currency', async () => {
    const onChange = jest.fn();
    render(
      <CurrencySelector
        options={[
          {
            title: 'All',
            currencies: [
              { code: 'USC', label: 'USDC', keywords: ['USC'] },
              { code: 'EUR', label: 'Euro', keywords: ['EUR'] },
            ],
          },
        ]}
        id="id"
        currency="EUR"
        labelId="labelId"
        onChange={onChange}
      />,
    );

    await userEvent.click(screen.getByRole('combobox'));
    await userEvent.click(screen.getByRole('option', { name: /^usdc/iu }));

    expect(onChange).toHaveBeenCalledWith('USC');
  });

  it('returns USC option when searching by the formatted code USDC', async () => {
    render(
      <CurrencySelector
        options={mockCurrencies}
        id="id"
        currency="USD"
        labelId="labelId"
        onChange={jest.fn()}
      />,
    );

    await userEvent.click(screen.getByRole('combobox', { name: 'Select currency' }));

    await userEvent.type(
      screen.getByRole('combobox', {
        name: /type a currency \/ country/iu,
      }),
      'USDC',
    );

    await waitFor(() => {
      expect(screen.getByRole('option', { name: /usdc/iu })).toBeInTheDocument();
    });
  });

  it('does not return USDC option when searching by the raw code USC', async () => {
    render(
      <CurrencySelector
        options={mockCurrencies}
        id="id"
        currency="USD"
        labelId="labelId"
        onChange={jest.fn()}
      />,
    );

    await userEvent.click(screen.getByRole('combobox', { name: 'Select currency' }));

    await userEvent.type(
      screen.getByRole('combobox', {
        name: /type a currency \/ country/iu,
      }),
      'USC',
    );

    await waitFor(() => {
      expect(screen.queryByRole('option')).not.toBeInTheDocument();
    });
  });

  it('deduplicates currencies while searching', async () => {
    render(
      <CurrencySelector
        options={mockCurrencies}
        id="id"
        currency="USD"
        labelId="labelId"
        onChange={jest.fn()}
      />,
    );

    await userEvent.click(screen.getByRole('combobox', { name: 'Select currency' }));

    await userEvent.type(
      screen.getByRole('combobox', {
        name: /type a currency \/ country/iu,
      }),
      'EUR',
    );

    expect(screen.getAllByRole('option')).toHaveLength(1);
  });
});

const mockCurrencies = [
  {
    title: 'Popular',
    currencies: [
      {
        code: 'USD',
        label: 'US Dollar',
        keywords: ['USD'],
      },
      {
        code: 'EUR',
        label: 'Euro',
        keywords: ['EUR'],
      },
    ],
  },
  {
    title: 'All',
    currencies: [
      {
        code: 'AED',
        label: 'United Arab Emirates Dirham',
        keywords: ['AED'],
      },
      {
        code: 'AFN',
        label: 'Afghan Afghani',
        keywords: ['AFN'],
      },
      {
        code: 'EUR',
        label: 'Euro',
        keywords: ['EUR', 'saudi arabia'],
      },
      {
        code: 'AUD',
        label: 'Australian Dollar',
        keywords: ['AUD', 'australia'],
      },
      {
        code: 'USC',
        label: 'Digital Dollar',
        keywords: ['USDC', 'Digital Dollar'],
      },
    ],
  },
];
