import { runSaga } from 'redux-saga';
import * as api from '../../request/usersRequest';
import { fireEvent, render, screen } from "@testing-library/react";
import * as redux from "react-redux";
import UsersPage from "../../pages/UsersPage/UsersPage";
import store from "../../store";
import "../../i18n";
import { mockState } from "../../mockState";
import {
  FETCH_USERS_REQ,
  TOGGLE_USER_ENABLE_REQ,
} from "../../store/actions/users/usersActionConstants";
import { Router } from "react-router-dom";
import history from "../../store/utils/history";
import { getUsers } from '../../store/saga/usersSaga';
import { setUsers, setUsersError } from '../../store/actions/users/usersActions';

describe("UsersPage render tests", () => {
  const cont = (
    <redux.Provider store={store}>
      <Router history={history}>
        <UsersPage />
      </Router>
    </redux.Provider>
  );

  let spyOnUseSelector;
  let spyOnUseDispatch;
  let mockDispatch;

  beforeEach(() => {
    // Mock useSelector hook
    spyOnUseSelector = jest.spyOn(redux, "useSelector");
    spyOnUseSelector.mockReturnValue(mockState.users);

    // Mock useDispatch hook
    spyOnUseDispatch = jest.spyOn(redux, "useDispatch");

    // Mock dispatch function returned from useDispatch
    mockDispatch = jest.fn();
    spyOnUseDispatch.mockReturnValue(mockDispatch);
  });

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

  it("Should dispatch get users request when rendered", () => {
    render(cont);
    expect(mockDispatch).toHaveBeenCalledWith({
      type: FETCH_USERS_REQ,
    });
  });

  it("Should dispatch disable/enable request when clicking on user disable btn", () => {
    const { container } = render(cont);
    // making the btns for editing visible
    fireEvent.click(screen.getAllByTestId("btn-testid")[0]);
    // clicking on disable btn for the first user
    fireEvent.click(container.getElementsByClassName("td-btn")[1]);

    // after clicking on disable for user with id = 1, it should dispatch the setEnableUsersReq with parameter 1 as id

    // can be done this way too
    // expect(mockDispatch).toHaveBeenLastCalledWith(setEnableUsersReq({ id: 1 }));


    expect(mockDispatch).toHaveBeenCalledWith({
      type: TOGGLE_USER_ENABLE_REQ,
      payload: {
        id: 1,
      },
    });
  });

  it('should load and handle users in case of success', async () => {
    // we push all dispatched actions to make assertions easier
    // and our tests less brittle
    const dispatchedActions = [];

    // we don't want to perform an actual api call in our tests
    // so we will mock the getAllUsers api with jest
    // this will mutate the dependency which we may reset if other tests
    // are dependent on it
    const mockedCall = { data: mockState.users.users };
    api.getAllUsers = jest.fn(() => Promise.resolve(mockedCall));

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

    // wait for saga to complete
    await runSaga(fakeStore, getUsers).done;
    let res = spyOnUseSelector();
    expect(api.getAllUsers.mock.calls.length).toBe(1);
    expect(dispatchedActions).toContainEqual(setUsers(mockedCall.data));
  });


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

    // we simulate an error by rejecting the promise
    // then we assert if our saga dispatched the action(s) correctly
    const error = { response: { data: { message: mockState.users.fetchUsersErrorMessage } } };
    api.getAllUsers = jest.fn(() => Promise.reject(error));

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

    await runSaga(fakeStore, getUsers).done;

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







