import * as appHooks from "@/app/hooks";
import { AppDispatch, setupStore } from "@/app/store";
import HandleLogin from "@/features/User/HandleLogin";
import * as oidcAuth from "@/features/User/oidcAuth";
import { clientConfig } from "@/features/User/oidcAuth";
import { useInitializeApp } from "@/features/User/useInitializeApp";
import * as apiUtils from "@/utils/apiUtils";
import { renderHook, screen, waitFor } from "@testing-library/react";
import { Provider } from "react-redux";
import { push } from "redux-first-history";
import { renderWithProviders } from "../../utils/Renderwithproviders";

clientConfig.url = "https://example.com";

describe("HandleLogin", () => {
  beforeEach(() => {
    jest.clearAllMocks();
    jest.spyOn(apiUtils, "redirectTo").mockImplementation(() => {});
    const dispatch = jest.fn() as AppDispatch;
    jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
    sessionStorage.clear();
    Object.defineProperty(window, "matchMedia", {
      writable: true,
      value: jest.fn().mockImplementation((query) => ({
        matches: false,
        media: query,
        onchange: null,
        addEventListener: jest.fn(),
        removeEventListener: jest.fn(),
        dispatchEvent: jest.fn(),
      })),
    });
  });

  test("redirects and sets sessionStorage when no userData", async () => {
    const loginUrlMock = {
      code_verifier: "verifier123",
      state: "state123",
      redirectTo: new URL("http://login.url"),
    };

    jest.spyOn(oidcAuth, "Auth").mockResolvedValue(loginUrlMock);

    const { result } = renderHook(() => useInitializeApp(), {
      wrapper: ({ children }) => (
        <Provider
          store={setupStore({
            user: {
              userData: null,
              tokens: null,
              loading: false,
              error: null,
              coreConfig: { language: "en" },
            },
            calendars: { list: {}, pending: false, error: null },
          })}
        >
          {children}
        </Provider>
      ),
    });

    await waitFor(
      () => {
        expect(oidcAuth.Auth).toHaveBeenCalled();
      },
      { timeout: 3000 }
    );

    await waitFor(
      () => {
        expect(sessionStorage.getItem("redirectState")).toEqual(
          JSON.stringify({
            code_verifier: "verifier123",
            state: "state123",
          })
        );
      },
      { timeout: 3000 }
    );

    await waitFor(
      () => {
        expect(apiUtils.redirectTo).toHaveBeenCalledWith(
          loginUrlMock.redirectTo
        );
      },
      { timeout: 3000 }
    );
  });

  test("does not render loading element when userData exists and calendars pending is true", () => {
    const preloadedState = {
      user: {
        userData: {
          sub: "test",
          email: "test@test.com",
          sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
          openpaasId: "667037022b752d0026472254",
        },
        tokens: { access_token: "test" },
        loading: false,
      },
      calendars: { list: {}, pending: true },
      loading: { isLoading: true },
    };

    renderWithProviders(<HandleLogin />, preloadedState);
    // HandleLogin now returns null, loading is shown at App level via appLoading state
    expect(screen.queryByTestId("loading")).not.toBeInTheDocument();
  });
  test("does not render loading element when userData exists and calendars pending is false", () => {
    const preloadedState = {
      user: {
        userData: {
          sub: "cmoussu",
          email: "cmoussu@linagora.com",
          sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
          openpaasId: "667037022b752d0026472254",
        },
        tokens: { access_token: "test" },
        loading: false,
      },
      calendars: { list: {}, pending: false },
      loading: { isLoading: false },
    };
    renderWithProviders(<HandleLogin />, preloadedState);

    // HandleLogin now returns null, loading is shown at App level via appLoading state
    expect(screen.queryByTestId("loading")).not.toBeInTheDocument();
  });
  test("goes to error page when there is error in user data", async () => {
    const mockDispatch = jest.fn();
    jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(mockDispatch);
    jest.spyOn(oidcAuth, "Auth").mockResolvedValue({
      code_verifier: "verifier123",
      state: "state123",
      redirectTo: new URL("http://login.url"),
    });

    renderWithProviders(<HandleLogin />, {
      user: {
        error: true,
        loading: false,
        userData: {
          sub: "test",
          email: "test@test.com",
          sid: "testSid",
          openpaasId: "testId",
        },
        tokens: { access_token: "test" },
      },
      calendars: {
        list: {},
        pending: false,
        error: null,
      },
    });

    await waitFor(
      () => {
        expect(mockDispatch).toHaveBeenCalledWith(push("/error"));
      },
      { timeout: 3000 }
    );
  });
});
