import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import * as redux from "react-redux";
import store from "../../store";
import { mockState } from "../../mockState";
import { Router } from "react-router-dom";
import history from "../../store/utils/history";
import TableViewPage from "../../pages/CandidatesPage/TableViewPage";
import { PAGE_SIZE_CANDIDATES } from "../../constants/keyCodeConstants";
import { getCV } from "../../request/candidatesRequest";

describe("TableViewPage render tests", () => {
  var props = {
    history: {
      replace: jest.fn(),
      push: jest.fn(),
      location: {
        pathname: "/candidates",
      },
    },
    setPage: jest.fn(),
    sliderValue: [0, 2],
    startingDate: "",
    endingDate: "",
    typesOfEmployments: [],
    technologie: [],
    page: 1,
  };

  const cont = (
    <redux.Provider store={store}>
      <Router history={history}>
        <TableViewPage search="" {...props} />
      </Router>
    </redux.Provider>
  );

  let spyOnUseSelector;
  let spyOnUseDispatch;
  let mockDispatch;

  beforeEach(() => {
    spyOnUseSelector = jest.spyOn(redux, "useSelector");
    spyOnUseSelector
      .mockReturnValueOnce(mockState.candidates.candidates)
      .mockReturnValueOnce(mockState.candidates.pagination);

    spyOnUseDispatch = jest.spyOn(redux, "useDispatch");
    mockDispatch = jest.fn();
    spyOnUseDispatch.mockReturnValue(mockDispatch);
  });

  afterEach(() => {
    jest.restoreAllMocks();
  });

  it("Should render", () => {
    const { container } = render(cont);
    expect(
      container.getElementsByClassName("candidates-table")[0]
    ).toBeDefined();
  });

  it("Should dispatch function when component is rendered", async () => {
    render(cont);
    await waitFor(() => expect(mockDispatch).toBeCalledTimes(1));
  });

  it("Should render table", () => {
    const { container } = render(cont);
    expect(container.getElementsByClassName("usersTable")[0]).toBeDefined();
  });

  it("Should render pagination component", () => {
    const { container } = render(cont);
    expect(
      container.getElementsByClassName("candidates-pagination")[0]
    ).toBeDefined();
  });

  it("Here we check if our component is displaying as many pages as it should display", () => {
    const { container } = render(cont);
    expect(
      container
        .getElementsByClassName("css-wjh20t-MuiPagination-ul")[0]
        .getElementsByTagName("li").length - 2 // we substract because list will contain left and right arrow
    ).toBe(
      parseInt(mockState.candidates.candidates.length) <= PAGE_SIZE_CANDIDATES
        ? 1
        : Math.ceil(
            parseInt(mockState.candidates.candidates.length) /
              PAGE_SIZE_CANDIDATES
          )
    );
  });

  it("The number of table rows should be equal to the number of candidates", () => {
    const { container } = render(cont);
    expect(container.getElementsByClassName("cadidate-row").length).toBe(
      mockState.candidates.candidates.length
    );
  });

  it("Should render candidate details page after clicking on table row", () => {
    const { container } = render(cont);
    fireEvent.click(container.getElementsByClassName("cadidate-row")[0]);
    const arg = { pathname: "/candidates/1" };
    expect(props.history.push).toHaveBeenCalledWith(arg);
  });

  it("Initially CV of candidate isn't displayed", () => {
    const { container } = render(cont);
    expect(
      container.getElementsByClassName("candidates-cv")[0].style.opacity
    ).toBe("0");
  });

  // How to mock constant?
  // it("When user change table page, function for fetching users should be called", async () => {
  //   const { container } = render(cont);
  //   const pag = container
  //     .getElementsByClassName("MuiPagination-ul")[0]
  //     .getElementsByTagName("li")[1]
  //     .querySelector("button");
  //   fireEvent.click(pag);
  //   await waitFor(() => expect(mockDispatch).toBeCalledTimes(2));
  // });

  it("Should render CV of candidate after clicking on CV name", async () => {
    let catchFn = jest.fn();
    const basse64Pdf = "some base64 string";
    getCV("name od pdf file")
      .then(() => basse64Pdf)
      .catch(catchFn);
    const { container } = render(cont);

    fireEvent.click(
      container
        .getElementsByClassName("cadidate-row")[0]
        .getElementsByTagName("td")[4]
        .getElementsByTagName("span")[0]
    );

    waitFor(() => {
      expect(
        container.getElementsByClassName("candidates-cv")[0].style.opacity
      ).toBe("1");
    });
  });
});
