import { render, fireEvent, screen, 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 CandidateDetailsPage from "../../pages/CandidatesPage/CandidateDetailsPage";
import mediaQuery from "css-mediaquery";

function createMatchMedia(width) {
  return (query) => ({
    matches: mediaQuery.match(query, { width }),
    addListener: () => {},
    removeListener: () => {},
  });
}

describe("CandidateDetailsPage render tests", () => {
  var props = {
    history: {
      replace: jest.fn(),
      push: jest.fn(),
      location: {
        pathname: "/candidates/1",
      },
    },
  };

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

  let spyOnUseSelector;
  let spyOnUseDispatch;
  let mockDispatch;

  beforeEach(() => {
    window.matchMedia = createMatchMedia(362);
    spyOnUseSelector = jest.spyOn(redux, "useSelector");
    spyOnUseSelector
      .mockReturnValueOnce(mockState.users.users)
      .mockReturnValueOnce(mockState.users.user)
      .mockReturnValueOnce(mockState.candidate.candidate)
      .mockReturnValueOnce(mockState.users.users)
      .mockReturnValueOnce(mockState.users.user)
      .mockReturnValueOnce(mockState.candidate.candidate)
      .mockReturnValueOnce(mockState.users.users)
      .mockReturnValueOnce(mockState.users.user)
      .mockReturnValueOnce(mockState.candidate.candidate);

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

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

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

  it("Initialy should dispatch two methods", () => {
    render(cont);
    expect(mockDispatch).toBeCalledTimes(2);
  });

  it("Should render candidate name", () => {
    const { container } = render(cont);
    expect(
      container.getElementsByClassName("candidate-lower-header")[0]
    ).toBeDefined();
  });

  it("Should render button for deleting candidate", () => {
    const { container } = render(cont);
    expect(container.getElementsByClassName("candidate-btn")[0]).toBeDefined();
  });

  it("Should represent one year of experience for the candidate", () => {
    render(cont);
    expect(screen.getByTestId("candidate-experience").textContent).toBe(
      "candidates.experience:1"
    );
  });

  it("Should represent all technologies of candidate", () => {
    const { container } = render(cont);
    expect(
      container.getElementsByClassName("technology-candidate-card").length
    ).toBe(2);
  });

  it("It should show Muski inside paragraph for gender because value of gender property of our candidate is M", () => {
    render(cont);
    expect(screen.getByTestId("candidate-gender").textContent).toBe("common.male");
  });

  it("Should render dialog after clicking button for deleting candidate", () => {
    const { container } = render(cont);
    fireEvent.click(container.getElementsByClassName("candidate-btn")[0]);
    expect(screen.getByTestId("alert-container")).toBeDefined();
  });

  it("Should render input for sending comment", () => {
    const { container } = render(cont);
    expect(container.getElementsByClassName("comment-input")[0]).toBeDefined();
  });

  it("Initially mention should not be rendered", async () => {
    const { container } = render(cont);
    await waitFor(() =>
      expect(
        container.getElementsByClassName("comment-input_suggestions")[0]
      ).toBeUndefined()
    );
  });

  it("Should render mention list after entering @ inside our mention input", async () => {
    const { container } = render(cont);
    const input = container
      .getElementsByClassName("comment-input")[0]
      .querySelector("textarea");

    waitFor(() => {
      fireEvent.change(input, { target: { value: "@" } });
      expect(
        container
          .getElementsByClassName("comment-input")[0]
          .getElementsByClassName("comment-input_suggestions")[0]
      ).toBeDefined();
    });
  });

  it("Should render first button for sending commment because width of screen is greater than 361", () => {
    const { container } = render(cont);
    expect(
      container.getElementsByClassName("comment-send-btn")[0]
    ).toBeDefined();
  });

  it("Clicking button for sending comment should dispatch function", async () => {
    const { container } = render(cont);
    const input = container
      .getElementsByClassName("comment-input")[0]
      .querySelector("textarea");
    fireEvent.change(input, { target: { value: "some value" } });
    fireEvent.click(container.getElementsByClassName("comment-send-btn")[0]);
    await waitFor(() => expect(mockDispatch).toBeCalledTimes(3));
  });

  it("Should not render second button for sending commment because width of screen is greater than 361", () => {
    const { container } = render(cont);
    expect(
      container.getElementsByClassName("comment-send-btn-responsive")[0]
    ).toBeUndefined();
  });

  it("Should render button for downloading CV", () => {
    const { container } = render(cont);
    expect(
      container.getElementsByClassName("applicant-cv-button")[0]
    ).toBeDefined();
  });

  it("should not render responsive right and left arrow because screen width is greater than 361", () => {
    render(cont);
    expect(screen.queryByTestId("candidate-ad-responsive-arrows")).toBeNull();
  });

  it("Should render two ads for candidate", () => {
    const { container } = render(cont);
    expect(container.getElementsByClassName("applicant-add").length).toBe(2);
  });

  it("Should render three comments", () => {
    const { container } = render(cont);
    expect(
      container.getElementsByClassName("comment-sub-container").length
    ).toBe(3);
  });

  it("Should render page with all candidates", () => {
    const { container } = render(cont);
    fireEvent.click(
      container.getElementsByClassName("applicant-ads-back-button")[0]
    );
    const arg = { pathname: "/candidates" };
    expect(props.history.push).toHaveBeenCalledWith(arg);
  });
});
