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 * as api from '../../request/usersRequest'
import UserDetails from "../../pages/UsersPage/UserDetails";
import ColorModeProvider from "../../context/ColorModeContext";
import {
  USER_DETAILS_REQ,
} from "../../store/actions/users/usersActionConstants";
import { userDetails } from "../../store/saga/usersSaga";
import { stateUserDetailsSuccess, userDetailsError } from "../../store/actions/users/usersActions";
import { runSaga } from "redux-saga";
import * as helper from "../../util/helpers/rejectErrorCodeHelper";

jest.mock("react-router-dom", () => ({
  ...jest.requireActual("react-router-dom"),
  useParams: () => ({
    id: 1,
  }),
}));

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

  let spyOnUseSelector;
  let spyOnUseDispatch;
  let mockDispatch;

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

    // 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 user details with params request when rendered", () => {
    render(cont);
    expect(mockDispatch).toHaveBeenCalledWith({
      type: USER_DETAILS_REQ,
      payload: { id: 1 },
    });
  });

  it("should run userDetails saga function with actions", async () => {
    const dispatchedActions = [];

    api.userDetailsRequest = jest.fn(() => Promise.resolve({ data: mockState.user.user }));

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

    const mock = jest.fn()

    await runSaga(fakeStore, userDetails, {
      payload: {
        id: 1,
        handleApiResponseSuccess: mock
      },
    }).done;

    expect(api.userDetailsRequest.mock.calls.length).toBe(1);
    expect(mock).toHaveBeenCalled();
    expect(dispatchedActions).toContainEqual(stateUserDetailsSuccess(mockState.user.user));
  });

  it("should handle error if exception occurs", async () => {
    const dispatchedActions = [];
    helper.rejectErrorCodeHelper = jest.fn(() =>  "Error");
    api.userDetailsRequest = jest.fn(() => Promise.reject({ response: {data:{message:"Error"}} }));

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

    await runSaga(fakeStore, userDetails, {
      payload: {
        id: 1,
      },
    }).done;

    expect(api.userDetailsRequest.mock.calls.length).toBe(1);
    expect(dispatchedActions).toContainEqual(userDetailsError("Error"));
  });
});
