import { h } from 'preact';
import { fireEvent, render } from '@testing-library/preact';
import { SearchFormSync } from '../SearchFormSync';

function setWindowLocation(url = '') {
  delete window.location; // Inspired from https://www.benmvp.com/blog/mocking-window-location-methods-jest-jsdom/
  window.location = new URL(url);
}

// a11y tests are not required for this component as it's job is to provide data to other components.
// There is nothing UI related about this component.
describe('<SearchFormSync />', () => {
  beforeEach(() => {
    // This part of the DOM would be rendered in the search results from the server side.
    // See search.html.erb.
    // It is where the portal will render.
    document.body.innerHTML =
      '<div id="mobile-search-container"><form></form></div>';

    setWindowLocation(`https://localhost:3000/`);

    global.InstantClick = jest.fn(() => ({
      on: jest.fn(),
      off: jest.fn(),
      preload: jest.fn(),
      display: jest.fn(),
    }))();
  });

  it('should synchronize search forms', async () => {
    const { getByRole, getAllByRole } = render(<SearchFormSync />);

    // Only one input is rendered at this point because the synchSearchForms custom event is what
    // tells us that there is a new search form to sync with the existing one.
    const searchInput = await getByRole('textbox', { name: /search/i });

    // Because window.location has no search term in it's URL
    expect(searchInput.value).toEqual('');

    // https://www.theatlantic.com/technology/archive/2012/09/here-it-is-the-best-word-ever/262348/
    const searchTerm = 'diphthong';

    // simulates a search result returned which contains the server side rendered search form for mobile only.
    setWindowLocation(`https://localhost:3000/search?q=${searchTerm}`);

    fireEvent(
      window,
      new CustomEvent('syncSearchForms', {
        detail: { querystring: window.location.search },
      }),
    );

    const [desktopSearch, mobileSearch] = await getAllByRole('textbox', {
      name: /search/i,
    });

    expect(desktopSearch.value).toEqual(searchTerm);
    expect(mobileSearch.value).toEqual(searchTerm);
  });

  it('should synchronize search forms on a subsequent search', async () => {
    const { getByRole, getAllByRole } = render(<SearchFormSync />);

    // Only one input is rendered at this point because the synchSearchForms custom event is what
    // tells us that there is a new search form to sync with the existing one.
    const searchInput = await getByRole('textbox', { name: /search/i });

    // Because window.location has no search term in it's URL
    expect(searchInput.value).toEqual('');

    // https://www.theatlantic.com/technology/archive/2012/09/here-it-is-the-best-word-ever/262348/
    const searchTerm = 'diphthong';

    // simulates a search result returned which contains the server side rendered search form for mobile only.
    setWindowLocation(`https://localhost:3000/search?q=${searchTerm}`);

    fireEvent(
      window,
      new CustomEvent('syncSearchForms', {
        detail: { querystring: window.location.search },
      }),
    );

    let [desktopSearch, mobileSearch] = await getAllByRole('textbox', {
      name: /search/i,
    });

    expect(desktopSearch.value).toEqual(searchTerm);
    expect(mobileSearch.value).toEqual(searchTerm);

    const searchTerm2 = 'diphthong2';

    // simulates a search result returned which contains the server side rendered search form for mobile only.
    setWindowLocation(`https://localhost:3000/search?q=${searchTerm2}`);

    const oldPortalContainer = document.getElementById(
      'mobile-search-container',
    );

    const newPortalContainer = oldPortalContainer.cloneNode(true);

    // This simulates the search results wiping out the old portal container
    // and providing a new portal container (different DOM elements).
    document.body.removeChild(oldPortalContainer);
    document.body.prepend(newPortalContainer);

    fireEvent(
      window,
      new CustomEvent('syncSearchForms', {
        detail: { querystring: window.location.search },
      }),
    );

    [desktopSearch, mobileSearch] = await getAllByRole('textbox', {
      name: /search/i,
    });

    expect(desktopSearch.value).toEqual(searchTerm2);
    expect(mobileSearch.value).toEqual(searchTerm2);
  });

  it('ensure both mobile search form & desktop search form exists', async () => {
    const { getAllByRole } = render(<SearchFormSync />);

    setWindowLocation(`https://localhost:3000/search`);

    // fire click event twice with empty query to mimic clicking search button twice present in header
    for (let i = 0; i < 2; i += 1) {
      fireEvent(
        window,
        new CustomEvent('syncSearchForms', {
          detail: { querystring: window.location.search },
        }),
      );
    }

    const forms = await getAllByRole('textbox', {
      name: /search/i,
    });

    expect(forms.length).toEqual(2);
  });
});
