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/scheduleRequest";
import { runSaga } from "redux-saga";
import { SCHEDULE_FETCH } from "../../store/actions/schedule/scheduleActionConstants";
import { getSchedule } from "../../store/saga/scheduleSaga";
import {
  fetchScheduleSuccess,
  fetchScheduleError,
} from "../../store/actions/schedule/scheduleActions";
import SchedulePage from "../../pages/SchedulePage/SchedulePage";
import ColorModeProvider from "../../context/ColorModeContext";
import * as helper from "../../util/helpers/rejectErrorCodeHelper";

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

  let spyOnUseSelector;
  let spyOnUseDispatch;
  let mockDispatch;

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

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

    mockDispatch = jest.fn();
    spyOnUseDispatch.mockReturnValue(mockDispatch);
  });

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

  it("Should dispatch get schedule request when rendered", () => {
    render(cont);
    const date = new Date()
    expect(mockDispatch).toHaveBeenCalledWith({
      type: SCHEDULE_FETCH,
      payload: {
        month: date.getMonth() + 1,
        year: date.getFullYear(),
      },
    });
  });

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

    const mockedCall = { data: mockState.schedule.schedule };
    api.getSpecificSchedule = jest.fn(() => Promise.resolve(mockedCall));

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

    await runSaga(fakeStore, getSchedule, {
      payload: {
        month: 12,
        year: 2022,
      },
    }).done;
    expect(api.getSpecificSchedule.mock.calls.length).toBe(1);
    expect(dispatchedActions).toContainEqual(fetchScheduleSuccess(mockedCall.data));
  });

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

    helper.rejectErrorCodeHelper = jest.fn(
      () => mockState.schedule.fetchScheduleErrorMessage
    );

    const error = {
      response: {
        data: { message: mockState.schedule.fetchScheduleErrorMessage },
      },
    };
    api.getSpecificSchedule = jest.fn(() => Promise.reject(error));

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

    await runSaga(fakeStore, getSchedule, {
      payload: {
        month: 12,
        year: 2022,
      },
    }).done;

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