import React from "react";
import { renderHook } from "@testing-library/react-hooks";
import { TuitioContext, TuitioDispatchContext } from "../../src/contexts";
import { useTuitioClient } from "../../src/hooks";
import { TuitioToken } from "@flare/tuitio-client";

jest.mock("@flare/tuitio-client", () => ({
  TuitioClient: jest.fn().mockImplementation(() => ({
    authenticate: jest.fn().mockResolvedValue({
      token: {
        raw: "mocked-token",
        validFrom: new Date(),
        validUntil: new Date()
      },
      status: "success"
    })
  })),
  invalidate: jest.fn(),
  fetch: jest.fn().mockResolvedValue({
    token: {
      raw: "mocked-token",
      validFrom: new Date(),
      validUntil: new Date()
    },
    userName: "user"
  })
}));

describe("useTuitioClient: dispatchActions", () => {
  let spyOnLoginSuccess: (token: TuitioToken, userName: string) => void;
  let spyOnLogout: () => void;

  beforeEach(() => {
    spyOnLoginSuccess = jest.fn();
    spyOnLogout = jest.fn();
  });

  afterEach(() => {
    (spyOnLoginSuccess as jest.Mock).mockReset();
    (spyOnLogout as jest.Mock).mockReset();
  });

  const tuitioContextState = {
    userName: "",
    token: {
      raw: "mocked-token",
      validFrom: new Date(),
      validUntil: new Date()
    },
    configuration: { tuitioUrl: null }
  };

  type Props = {
    children: React.ReactNode;
  };

  const wrapper = ({ children }: Props) => (
    <TuitioContext.Provider value={tuitioContextState}>
      <TuitioDispatchContext.Provider value={{ onLoginSuccess: spyOnLoginSuccess, onLogout: spyOnLogout }}>
        {children}
      </TuitioDispatchContext.Provider>
    </TuitioContext.Provider>
  );

  const optionMock = {
    onLoginSuccess: jest.fn(),
    onLoginFailed: jest.fn(),
    onLoginError: jest.fn()
  };

  it("onLoginSuccess should be called when user logs in", async () => {
    const { result } = renderHook(() => useTuitioClient(optionMock), { wrapper });

    const userName = "user";
    const password = "password";
    const response = await result.current.login(userName, password);

    expect(spyOnLoginSuccess).toHaveBeenCalledWith(response.token, userName);
  });

  it("onLogout should be called when user logs out", () => {
    const { result } = renderHook(() => useTuitioClient(optionMock), { wrapper });
    result.current.logout();
    expect(spyOnLogout).toHaveBeenCalled();
  });
});
