// Copyright (c) 2023 Tudor Stanciu

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

const userName = "tuitio.user";
const token = "mocked-token";
const expiresIn = 600000;

jest.mock("@flare/tuitio-client", () => ({
  TuitioClient: jest.fn().mockImplementation(() => ({
    login: jest.fn().mockResolvedValue({
      result: { token, expiresIn, validUntil: new Date() },
      error: null
    }),
    logout: jest.fn().mockResolvedValue({
      result: { userId: 0, userName, logoutDate: new Date() },
      error: null
    })
  })),
  acquire: jest.fn().mockResolvedValue({
    token,
    validUntil: new Date(),
    userName
  })
}));

describe("useTuitioClient: dispatchActions", () => {
  let spyOnLoginSuccess: (token: string, validUntil: Date, userName: string) => void;
  let spyOnLogoutSuccess: () => void;

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

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

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

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

  const wrapper = ({ children }: Props) => (
    <TuitioContext.Provider value={tuitioContextState}>
      <TuitioDispatchContext.Provider
        value={{
          onLoginSuccess: spyOnLoginSuccess,
          onLogoutSuccess: spyOnLogoutSuccess,
          onUserInfoLoaded: jest.fn()
        }}
      >
        {children}
      </TuitioDispatchContext.Provider>
    </TuitioContext.Provider>
  );

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

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

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

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

  it("onLogoutSuccess should be called when user logs out", async () => {
    const { result } = renderHook(() => useTuitioClient(optionsMock), { wrapper });
    await result.current.logout();
    expect(spyOnLogoutSuccess).toHaveBeenCalled();
  });
});
