jest.mock("../Contexts/CarUpdatesContext");
jest.mock("../Contexts/VehicleContext");
jest.mock("../Contexts/ManifestsContext");
jest.mock("../Contexts/UserContext");
jest.mock("../Contexts/IssueContext");
jest.mock("../../services/monitoring");
jest.mock("../../services/vehiclesAPI");
jest.mock("../../services/superset");
jest.mock("../../services/suppliersAPI");
jest.mock("../../services/issueAPI");

import {
  act, cleanup, render,
  screen, waitFor,
  waitForElementToBeRemoved
} from "@testing-library/react";
import App from ".";
import addSnapshotSerializer from "../../utils/snapshot";
import { TEST_AUTH_OBJECT_FISKER, TEST_AUTH_OBJECT_MAGNA } from "../../utils/testing";
import { setToken } from "../Contexts/UserContext";
import structuredClone from '@ungap/structured-clone';

const LOADING_STATUS = "Loading...";

const renderRoute = async (route) => {
  window.history.pushState({}, "", route);
  const { container } = render(<App />);
  if (screen.queryByText(LOADING_STATUS)) {
    await waitForElementToBeRemoved(() => screen.getByText(LOADING_STATUS));
  }
  return container;
};

const check = async (path, selector, compare) => {
  let container
  await act(async () => {
    container = await renderRoute(path);
  });
  expect(container.querySelector(selector).innerHTML).toEqual(compare);
  expect(container).toMatchSnapshot();
};

const sleepAndCheck = async (path, selector, compare) => {
  const container = await renderRoute(path);
  await waitFor(() => { });
  expect(container.querySelector(selector).innerHTML).toEqual(compare);
  expect(container).toMatchSnapshot();
};

describe("App", () => {
  beforeAll(() => {
    global.URL.createObjectURL = jest.fn();
    addSnapshotSerializer(expect);
    jest.setTimeout(10000);

    if (!("structuredClone" in global)) {
      global.structuredClone = structuredClone;
    }
  }, 60000);

  afterEach(() => {
    setToken(null);
    cleanup();
  });

  it("Route / unauthenticated", async () => {
    await sleepAndCheck("/", "span.MuiButton-label", "Sign In");
  });

  it("Route /home unauthenticated", async () => {
    await sleepAndCheck("/home", "span.MuiButton-label", "Sign In");
  });

  it("Route /packages unauthenticated", async () => {
    await check("/packages", "span.MuiButton-label", "Sign In");
  });

  it("Route /package-status unauthenticated", async () => {
    await check("/package-status/1", "span.MuiButton-label", "Sign In");
  });

  it("Route /package-deploy unauthenticated", async () => {
    await check("/package-deploy/1", "span.MuiButton-label", "Sign In");
  });

  it("Route /vehicle-add unauthenticated", async () => {
    await check("/vehicle-add", "span.MuiButton-label", "Sign In");
  });

  it("Route /issues unauthenticated", async () => {
    await check("/issues", "span.MuiButton-label", "Sign In");
  });

  it("Route /issue-info unauthenticated", async () => {
    await check("/issue-info/FISKER123", "span.MuiButton-label", "Sign In");
  });

  it("Route /vehicles unauthenticated", async () => {
    await check("/vehicles", "span.MuiButton-label", "Sign In");
  });

  it("Route /vehicle-status unauthenticated", async () => {
    await check("/vehicle-status/FISKER123", "span.MuiButton-label", "Sign In");
  });

  it("Route /vehicle-status/vin/carupdateid unauthenticated", async () => {
    await check(
      "/vehicle-status/1G1FP87S3GN100062/283",
      "span.MuiButton-label",
      "Sign In"
    );
  });

  it("Route /supplier/{email} unauthenticated", async () => {
    await check(
      "/supplier/test@supplier.com",
      "span.MuiButton-label",
      "Sign In"
    );
  });

  it("Route /tools/certificates/add unauthenticated", async () => {
    await check("/tools/certificates/add", "span.MuiButton-label", "Sign In");
  });

  it("Route /tools/sms/send unauthenticated", async () => {
    await check("/tools/sms/send", "span.MuiButton-label", "Sign In");
  });

  it("Route /tools/security-dll unauthenticated", async () => {
    await check("/tools/security-dll", "span.MuiButton-label", "Sign In");
  });

  it("Route /dashboards/0 unauthenticated", async () => {
    await check("/dashboards/0", "span.MuiButton-label", "Sign In");
  });

  it("Route /page-not-found unauthenticated", async () => {
    await check("/page-not-found", "h1", "Page Not Found");
  });

  it("Route / authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await sleepAndCheck("/", "h6", "Home");
  });

  it("Route /home authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await sleepAndCheck("/home", "h6", "Home");
  });

  it("Route /page-not-found authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/page-not-found", "h1", "Page Not Found");
  });

  it("Route /packages authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/packages", "h6", "Deployments");
  });

  it("Route /package-status authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/package-status/1", "h6", "Manifest Test Manifest 1.0");
  });

  it("Route /package-deploy authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/package-deploy/1", "h6", "Deploy Test Manifest 1.0");
  });

  it("Route /vehicle-add authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/vehicle-add", "h6", "Add Vehicle");
  });

  it("Route /vehicles authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/vehicles", "h6", "Vehicles");
  });

  it("Route /issues authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/issues", "h6", "Issues");
  });

  it("Route /issue-info authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/issue-info/FISKER123", "h6", "Issue FISKER123 Details");
  });


  it("Route /vehicle-status authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/vehicle-status/FISKER123", "h6", "Vehicle FISKER123 Details");
  });

  it("Route /tools/certificates/add authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await sleepAndCheck("/tools/certificates/add", "h6", "Create Certificate");
  });

  it("Route /tools/sms/send authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await sleepAndCheck("/tools/sms/send", "h6", "Send SMS");
  });

  it("Route /tools/security-dll authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_MAGNA);
    await sleepAndCheck("/tools/security-dll", "h6", "Security.dll Download");
  });

  it("Route /dashboards/0 authenticated", async () => {
    setToken(TEST_AUTH_OBJECT_FISKER);
    await check("/dashboards/0", "h6", "Datascope");
  });
});
