import {
  createV2SelfManagedLabMeta,
  createV2ServerlessLabMeta,
  mockedCreateServerlessLabCluster,
  mockedListServerlessClusters,
  mockedV2CreateLabInstance,
  mockLabsApi,
} from "@/testutils/mock-lab";
import { mockedGetMe, normalTestUser } from "@/testutils/mock-me-context";
import { mockNextNavigationModule } from "@/testutils/mock-next-navigation";
import { enableActx, useActx } from "@/testutils/use-actx";
import { act, queries, queryByRole, render } from "@testing-library/react";
import { expect, suite, test, vitest } from "vitest";

enableActx();
mockNextNavigationModule();
mockLabsApi();

suite("<DeployLabForm version={2} />", () => {
  test.each([
    import("@/components/labs/deploy-lab-form"),
    import("@/components/labs/deploy-lab-form.self-managed"),
  ])("self managed", async (module) => {
    const actx = useActx();

    const { ProvidersWrapper } = await import("@/testutils/providers");
    const { default: DeployLabForm } = await module;

    const testSelfManagedLab = createV2SelfManagedLabMeta();

    mockedGetMe.mockReturnValue(normalTestUser);
    mockedV2CreateLabInstance.mockReturnValue(
      Promise.resolve({
        lab_instance_id: 1001,
      })
    );

    const handleChange = vitest.fn();

    const ui = await act(() => {
      return render(
        <DeployLabForm
          tidbEnvironment="TiDB Self-Managed"
          lab={testSelfManagedLab}
          onChange={handleChange}
        />,
        {
          wrapper: ProvidersWrapper,
          queries,
        }
      );
    });

    // Select Tokyo as defaults region.
    const regionSelectorTrigger = ui.queryByLabelText(
      "Region"
    )! as HTMLButtonElement;
    expect(regionSelectorTrigger.disabled).toBeFalsy();
    expect(regionSelectorTrigger).toHaveTextContent("Tokyo");

    // Select Latest Version
    const versionsSelectorTrigger = ui.queryByLabelText(
      "Version or Product"
    )! as HTMLButtonElement;
    expect(versionsSelectorTrigger.disabled).toBeFalsy();
    expect(versionsSelectorTrigger).toHaveTextContent("2.0.0");

    const button = ui.queryByRole("button", {
      name: "Start",
    })! as HTMLButtonElement;
    expect(button.disabled).toBeFalsy();

    await actx(() => {
      button.click();
    });

    expect(mockedV2CreateLabInstance).toHaveBeenCalledOnce();
  });

  test.each([
    import("@/components/labs/deploy-lab-form"),
    import("@/components/labs/deploy-lab-form.serverless"),
  ])("serverless", async (module) => {
    const actx = useActx();

    const { ProvidersWrapper } = await import("@/testutils/providers");
    const { default: DeployLabForm } = await module;
    const mockedLocation = vitest.spyOn(window, "location", "get");
    const mockedSetLocation = vitest.fn<(value: string) => void>();

    mockedLocation.mockReturnValue({
      set href(value: string) {
        mockedSetLocation(value);
      },
    } as any);

    const testSelfManagedLab = createV2ServerlessLabMeta();

    mockedGetMe.mockReturnValue(normalTestUser);
    mockedV2CreateLabInstance.mockReturnValue(
      Promise.resolve({
        lab_instance_id: 1002,
      })
    );

    const handleChange = vitest.fn();

    const ui = await act(() => {
      return render(
        <DeployLabForm
          lab={testSelfManagedLab}
          onChange={handleChange}
          tidbEnvironment="TiDB Cloud Starter"
        />,
        {
          wrapper: ProvidersWrapper,
          queries,
        }
      );
    });

    // Select Tokyo as defaults region.
    const regionSelectorTrigger = ui.queryByLabelText(
      "Region"
    )! as HTMLButtonElement;
    expect(regionSelectorTrigger.disabled).toBeFalsy();
    expect(regionSelectorTrigger).toHaveTextContent("Tokyo");

    // Select Latest Version
    const versionsSelectorTrigger = ui.queryByLabelText(
      "TiDB Version"
    )! as HTMLButtonElement;
    expect(versionsSelectorTrigger).toBe(null);

    const authorize = ui.queryByRole("button", {
      name: "Authorize",
    })! as HTMLButtonElement;

    await actx(() => {
      authorize.click();
    });

    expect(mockedSetLocation).toHaveBeenCalledOnce();
    const authorizeHref = mockedSetLocation.mock.calls[0]?.[0];
    const authorizeUrl = new URL(authorizeHref, "http://localhost");
    const next = authorizeUrl.searchParams.get("next");
    expect(next).toBeTruthy();
    const nextUrl = new URL(next!, "http://localhost");
    expect(nextUrl.pathname).toBe("/lab");
    expect(nextUrl.searchParams.get("preview")).toBe("test_000");
    expect(nextUrl.searchParams.get("region")).toBe("aws:tokyo");
  });

  test("serverless with grant id, creating with existed", async () => {
    const actx = useActx();
    const { ProvidersWrapper } = await import("@/testutils/providers");
    const { default: DeployLabForm } = await import(
      "@/components/labs/deploy-lab-form"
    );
    const mockedLocation = vitest.spyOn(window, "location", "get");
    const mockedSetLocation = vitest.fn<(value: string) => void>();

    mockedLocation.mockReturnValue({
      set href(value: string) {
        mockedSetLocation(value);
      },
    } as any);

    const testSelfManagedLab = createV2ServerlessLabMeta();

    mockedGetMe.mockReturnValue(normalTestUser);
    mockedV2CreateLabInstance.mockReturnValue(
      Promise.resolve({
        lab_instance_id: 1003,
      })
    );
    mockedListServerlessClusters.mockReturnValue(
      Promise.resolve([
        {
          cluster_id: "1",
          display_name: "Example Cluster",
          region: "some",
          cloud_provider: "aws",
        },
      ])
    );
    mockedCreateServerlessLabCluster.mockReturnValue(
      Promise.resolve({
        cluster_id: "test_cluster_id",
      })
    );

    const handleChange = vitest.fn();

    const ui = await act(() => {
      return render(
        <DeployLabForm
          lab={testSelfManagedLab}
          tidbEnvironment="TiDB Cloud Starter"
          onChange={handleChange}
          serverlessGrantId={1}
        />,
        {
          wrapper: ProvidersWrapper,
          queries,
        }
      );
    });

    // Select Tokyo as defaults region.
    const regionSelectorTrigger = ui.queryByLabelText(
      "Region"
    )! as HTMLButtonElement;
    expect(regionSelectorTrigger.disabled).toBeFalsy();
    expect(regionSelectorTrigger).toHaveTextContent("Tokyo");

    // Select Latest Version
    const versionsSelectorTrigger = ui.queryByLabelText(
      "TiDB Version"
    )! as HTMLButtonElement;
    expect(versionsSelectorTrigger).toBe(null);

    const select = ui.queryByRole("button", {
      name: "Select Starter Cluster",
    })!;
    expect(select).toHaveTextContent("Loading...");
    await actx(async () => {});
    expect(select).toHaveTextContent("Select Cluster...");

    await actx(() => {
      select.click();
    });

    const option = ui.queryByRole("option", { name: "Example Cluster some" })!;

    await actx(() => {
      option.click();
    });

    expect(select).toHaveTextContent("Example Cluster");

    const button = ui.queryByRole("button", {
      name: "Start",
    })! as HTMLButtonElement;
    expect(button.disabled).toBeFalsy();

    await actx(() => {
      button.click();
    });

    const dialog = ui.queryByRole("alertdialog", {
      name: "This lab starts with an existing cluster in your own account.",
    })!;
    const startButton = queryByRole(dialog, "button", {
      name: "Start",
    })! as HTMLButtonElement;

    await actx(() => {
      startButton.click();
    });

    // Called the create cluster api using existed cluster
    expect(mockedCreateServerlessLabCluster).toHaveBeenCalledExactlyOnceWith(
      1,
      { cluster_id: "1" }
    );
    expect(mockedV2CreateLabInstance).toHaveBeenCalledExactlyOnceWith({
      lab_code: "test_000",
      tidb_environment: "TiDB Cloud Starter",
      cloud_provider: "aws",
      region_name: "tokyo",
      tidb_version: undefined,
      serverless_cluster_type: "user-host",
      user_serverless_cluster_id: "test_cluster_id",
    });
  });

  test("serverless with grant id, creating with new cluster", async () => {
    const actx = useActx();
    const { ProvidersWrapper } = await import("@/testutils/providers");
    const { default: DeployLabForm } = await import(
      "@/components/labs/deploy-lab-form"
    );
    const mockedLocation = vitest.spyOn(window, "location", "get");
    const mockedSetLocation = vitest.fn<(value: string) => void>();

    mockedLocation.mockReturnValue({
      set href(value: string) {
        mockedSetLocation(value);
      },
    } as any);

    const testSelfManagedLab = createV2ServerlessLabMeta();

    mockedGetMe.mockReturnValue(normalTestUser);
    mockedV2CreateLabInstance.mockReturnValue(
      Promise.resolve({
        lab_instance_id: 1004,
      })
    );
    mockedListServerlessClusters.mockReturnValue(
      Promise.resolve([
        {
          cluster_id: "1",
          display_name: "Example Cluster",
          region: "some",
          cloud_provider: "aws",
        },
      ])
    );
    mockedCreateServerlessLabCluster.mockReturnValue(
      Promise.resolve({
        cluster_id: "test_cluster_id",
      })
    );

    const handleChange = vitest.fn();

    const ui = await act(() => {
      return render(
        <DeployLabForm
          lab={testSelfManagedLab}
          tidbEnvironment="TiDB Cloud Starter"
          onChange={handleChange}
          serverlessGrantId={1}
        />,
        {
          wrapper: ProvidersWrapper,
          queries,
        }
      );
    });

    // Select Tokyo as defaults region.
    const regionSelectorTrigger = ui.queryByLabelText(
      "Region"
    )! as HTMLButtonElement;
    expect(regionSelectorTrigger.disabled).toBeFalsy();
    expect(regionSelectorTrigger).toHaveTextContent("Tokyo");

    // Select Latest Version
    const versionsSelectorTrigger = ui.queryByLabelText(
      "TiDB Version"
    )! as HTMLButtonElement;
    expect(versionsSelectorTrigger).toBe(null);

    const select = ui.queryByRole("button", {
      name: "Select Starter Cluster",
    })!;
    expect(select).toHaveTextContent("Loading...");
    await actx(async () => {});
    expect(select).toHaveTextContent("Select Cluster...");

    await actx(() => {
      select.click();
    });

    const option = ui.queryByRole("option", { name: "Create New Cluster" })!;

    await actx(() => {
      option.click();
    });

    expect(select).toHaveTextContent("Create New Cluster");

    const button = ui.queryByRole("button", {
      name: "Start",
    })! as HTMLButtonElement;
    expect(button.disabled).toBeFalsy();

    await actx(() => {
      button.click();
    });

    // Called the create cluster api using existed cluster
    expect(mockedCreateServerlessLabCluster).toHaveBeenCalledExactlyOnceWith(
      1,
      { region: "aws:tokyo" }
    );
    expect(mockedV2CreateLabInstance).toHaveBeenCalledExactlyOnceWith({
      lab_code: "test_000",
      tidb_environment: "TiDB Cloud Starter",
      cloud_provider: "aws",
      region_name: "tokyo",
      tidb_version: undefined,
      serverless_cluster_type: "user-host",
      user_serverless_cluster_id: "test_cluster_id",
    });
  });
});
