import * as redux from "react-redux";
import store from "../../store";
import { Router } from "react-router-dom";
import history from "../../store/utils/history";
import { mockState } from "../../mockState";
import { render } from "@testing-library/react";
import { FILTER_CANDIDATES } from "../../store/actions/candidates/candidatesActionConstants";
import TableViewPage from "../../pages/CandidatesPage/TableViewPage";
import * as api from "../../request/candidatesRequest";
import { runSaga } from "redux-saga";

import * as fc from "../../store/saga/candidatesSaga";
import {
  filterCandidatesSuccess,
  filterCandidatesError,
} from "../../store/actions/candidates/candidatesActions";
import { PAGE_SIZE_CANDIDATES } from "../../constants/keyCodeConstants";
import * as helper from "../../util/helpers/rejectErrorCodeHelper";

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,
    search: "",
  };
  const cont = (
    <redux.Provider store={store}>
      <Router history={history}>
        <TableViewPage {...props} />
      </Router>
    </redux.Provider>
  );

  let spyOnUseSelector;
  let spyOnUseDispatch;
  let mockDispatch;

  beforeEach(() => {
    // Mock useSelector hook
    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 dispatch filter candidates request when rendered", () => {
    render(cont);
    expect(mockDispatch).toHaveBeenCalledWith({
      type: FILTER_CANDIDATES,
      payload: {
        currentPage: 1,
        employmentType: "",
        maxDateOfApplication: "",
        maxExperience: 0,
        minDateOfApplication: "",
        minExperience: 0,
        pageSize: PAGE_SIZE_CANDIDATES,
        technologies: [],
      },
    });
  });

  it("should load and handle candidates in case of success", async () => {
    const dispatchedActions = [];

    const mockedCall = { data: mockState.candidates.items };
    api.getFilteredCandidates = jest.fn(() => Promise.resolve(mockedCall));

    const fakeStore = {
      getState: () => mockState.candidates.items,
      dispatch: (action) => dispatchedActions.push(action),
    };

    await runSaga(fakeStore, fc.filterCandidates, {}).done;
    expect(api.getFilteredCandidates.mock.calls.length).toBe(1);
    expect(dispatchedActions).toContainEqual(
      filterCandidatesSuccess(mockedCall.data)
    );
  });

  it("should handle technologies load errors in case of failure", async () => {
    const dispatchedActions = [];

    helper.rejectErrorCodeHelper = jest.fn(
      () => mockState.candidates.fetchCandidatesErrorMessage
    );

    const error = {
      response: {
        data: { message: mockState.candidates.fetchCandidatesErrorMessage },
      },
    };
    api.getFilteredCandidates = jest.fn(() => Promise.reject(error));

    const fakeStore = {
      getState: () => mockState.candidates.candidates,
      dispatch: (action) => dispatchedActions.push(action),
    };

    await runSaga(fakeStore, fc.filterCandidates, {}).done;

    expect(api.getFilteredCandidates.mock.calls.length).toBe(1);
    expect(dispatchedActions).toContainEqual(
      filterCandidatesError(error.response.data.message)
    );
  });
});
