import { expect, test } from "@playwright/test";

type TenantFixture = {
  id: string;
  type: string;
  name: string;
  slug: string;
  description: string;
  status: string;
  parentId?: string;
  config?: Record<string, unknown>;
  memberCount: number;
  createdAt: string;
  updatedAt: string;
};

function tenant(
  id: string,
  name: string,
  slug: string,
  parentId?: string,
): TenantFixture {
  return {
    id,
    type: parentId ? "USER_GROUP" : "COMPANY",
    name,
    slug,
    description: "",
    status: "active",
    parentId,
    memberCount: 1,
    createdAt: "2026-04-01T00:00:00.000Z",
    updatedAt: "2026-04-01T00:00:00.000Z",
  };
}

function user(id: string, name: string, companyCode: string) {
  return {
    id,
    email: `${id}@example.com`,
    name,
    role: "user",
    status: "active",
    companyCode,
    grade: "사원",
    createdAt: "2026-04-01T00:00:00.000Z",
    updatedAt: "2026-04-01T00:00:00.000Z",
  };
}

test("org chart viewport pans with drag and zooms with the mouse wheel", async ({
  page,
}) => {
  await page.route("**/api/v1/public/orgchart**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        sharedWith: "Playwright",
        tenants: [
          tenant("root", "Baron Group", "baron"),
          tenant("engineering", "Engineering", "engineering", "root"),
          tenant("platform", "Platform", "platform", "engineering"),
          tenant("security", "Security", "security", "engineering"),
          tenant("product", "Product", "product", "root"),
          tenant("design", "Design", "design", "product"),
          tenant("operations", "Operations", "operations", "root"),
        ],
        users: [
          user("u-root", "Root User", "baron"),
          user("u-eng", "Engineering User", "engineering"),
          user("u-platform", "Platform User", "platform"),
          user("u-security", "Security User", "security"),
          user("u-product", "Product User", "product"),
          user("u-design", "Design User", "design"),
          user("u-ops", "Operations User", "operations"),
        ],
      }),
    });
  });

  await page.goto("/chart?token=pan-zoom");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  const viewport = page.locator('[data-testid="orgchart-viewport"]');
  const canvas = page.locator('[data-testid="orgchart-canvas"]');
  const svg = page.locator('[data-testid="orgchart-vector-svg"]');
  await expect(viewport).toBeVisible();
  await expect(canvas).toBeVisible();
  await expect(svg).toBeVisible();

  await expect
    .poll(async () =>
      viewport.evaluate((element) => {
        const style = window.getComputedStyle(element);
        return `${style.overflowX}/${style.overflowY}`;
      }),
    )
    .toBe("hidden/hidden");

  const initialViewBox = await svg.getAttribute("viewBox");
  const box = await viewport.boundingBox();
  expect(box).not.toBeNull();

  if (!box) return;

  await page.mouse.move(box.x + 24, box.y + box.height - 24);
  await page.mouse.down();
  await page.mouse.move(box.x + 164, box.y + box.height - 104);
  await page.mouse.up();

  await expect
    .poll(async () => svg.getAttribute("viewBox"))
    .not.toBe(initialViewBox);

  const afterDragViewBox = await svg.getAttribute("viewBox");

  await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
  await page.mouse.wheel(0, -500);

  await expect
    .poll(async () => svg.getAttribute("viewBox"))
    .not.toBe(afterDragViewBox);

  const scale = await svg.evaluate((element) =>
    Number.parseFloat(element.getAttribute("data-scale") ?? "1"),
  );
  expect(scale).toBeGreaterThan(1);
});

test("org chart dashboard uses the full screen below the orgfront topbar", async ({
  page,
}) => {
  await page.route("**/api/v1/public/orgchart**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        sharedWith: "Playwright",
        tenants: [
          tenant("root", "Baron Group", "baron"),
          tenant("engineering", "Engineering", "engineering", "root"),
        ],
        users: [
          user("u-root", "Root User", "baron"),
          user("u-eng", "Engineering User", "engineering"),
        ],
      }),
    });
  });

  await page.goto("/chart?token=full-screen");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  const metrics = await page.evaluate(() => {
    const topbar = document
      .querySelector('[data-testid="orgfront-topbar"]')
      ?.getBoundingClientRect();
    const main = document
      .querySelector('[data-testid="orgfront-main"]')
      ?.getBoundingClientRect();
    const shell = document
      .querySelector('[data-testid="orgchart-dashboard-shell"]')
      ?.getBoundingClientRect();

    if (!topbar || !main || !shell) {
      throw new Error("Missing org chart layout elements");
    }

    return {
      innerHeight: window.innerHeight,
      innerWidth: window.innerWidth,
      mainTop: main.top,
      shellBottom: shell.bottom,
      shellLeft: shell.left,
      shellRight: shell.right,
      shellTop: shell.top,
      topbarBottom: topbar.bottom,
    };
  });

  expect(Math.abs(metrics.mainTop - metrics.topbarBottom)).toBeLessThanOrEqual(
    1,
  );
  expect(metrics.shellTop).toBe(metrics.topbarBottom);
  expect(metrics.shellLeft).toBeLessThanOrEqual(1);
  expect(metrics.shellRight).toBeGreaterThanOrEqual(metrics.innerWidth - 1);
  expect(metrics.shellBottom).toBeGreaterThanOrEqual(metrics.innerHeight - 1);
});

test("org chart non-shared title does not render the MH Dashboard eyebrow", async ({
  page,
}) => {
  await page.addInitScript(() => {
    window.localStorage.setItem("playwright_auth_bypass", "1");
    window.localStorage.setItem("dev_tenant_id", "group");
  });

  await page.route("**/api/v1/admin/orgchart/snapshot**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        tenants: [
          {
            ...tenant("group", "Baron Group", "baron"),
            type: "COMPANY_GROUP",
          },
          tenant("engineering", "Engineering", "engineering", "group"),
        ],
        users: [user("u-eng", "Engineering User", "engineering")],
        cache: { source: "redis", hit: true },
      }),
    });
  });

  await page.goto("/chart");

  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();
  await expect(page.getByText("MH Dashboard", { exact: true })).toHaveCount(0);
});

test("org chart toggles internal organizations from the total users tooltip", async ({
  page,
}) => {
  await page.addInitScript(() => {
    window.localStorage.setItem("playwright_auth_bypass", "1");
    window.localStorage.setItem("dev_tenant_id", "group");
  });

  await page.route("**/api/v1/admin/orgchart/snapshot**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        tenants: [
          {
            ...tenant("group", "한맥가족", "hanmac-family"),
            type: "COMPANY_GROUP",
          },
          tenant("company", "삼안", "saman", "group"),
          {
            ...tenant("open-team", "공개 팀", "open-team", "company"),
            config: { visibility: "public" },
          },
          {
            ...tenant("internal-team", "내부 팀", "internal-team", "company"),
            config: { visibility: "internal" },
          },
        ],
        users: [
          user("u-open", "Open User", "open-team"),
          user("u-internal", "Internal User", "internal-team"),
        ],
        cache: { source: "redis", hit: true },
      }),
    });
  });

  await page.goto("/chart");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  const svg = page.locator('[data-testid="orgchart-vector-svg"]');
  const totalUsersControl = page.getByTestId("orgchart-total-users-control");
  await expect(totalUsersControl).toHaveText("총 1명");
  await expect(svg.getByText("공개 팀", { exact: true })).toBeVisible();
  await expect(svg.getByText(/Open User/)).toBeVisible();
  await expect(svg.getByText("내부 팀", { exact: true })).toHaveCount(0);
  await expect(svg.getByText("Internal User", { exact: true })).toHaveCount(0);

  await totalUsersControl.hover();
  await page.getByRole("switch", { name: "내부조직 보기" }).setChecked(true);

  await expect(totalUsersControl).toHaveText("총 2명");
  await expect(svg.getByText("내부 팀", { exact: true })).toBeVisible();
  await expect(svg.getByText(/Internal User/)).toBeVisible();
});

test("org chart defaults to hanmac family when public sector group is listed first", async ({
  page,
}) => {
  await page.addInitScript(() => {
    window.localStorage.setItem("playwright_auth_bypass", "1");
    window.localStorage.setItem("dev_tenant_id", "family");
  });

  await page.route("**/api/v1/admin/orgchart/snapshot**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        tenants: [
          {
            ...tenant("public-sector", "공공기관", "public-sector"),
            type: "COMPANY_GROUP",
            memberCount: 0,
          },
          {
            ...tenant("family", "한맥가족", "hanmac-family"),
            type: "COMPANY_GROUP",
          },
          {
            ...tenant("saman", "삼안", "saman", "family"),
            type: "COMPANY",
          },
        ],
        users: [user("u-saman", "Saman User", "saman")],
        cache: { source: "redis", hit: true },
      }),
    });
  });

  await page.goto("/chart");

  const svg = page.locator('[data-testid="orgchart-vector-svg"]');
  await expect(
    page.getByRole("button", { name: "조직: 한맥가족" }),
  ).toBeVisible();
  await expect(svg.getByText("한맥가족", { exact: true })).toBeVisible();
  await expect(svg.getByText("삼안", { exact: true })).toBeVisible();
  await expect(svg.getByText("공공기관", { exact: true })).toHaveCount(0);
});

test("org chart renders dense member nodes with calculated member columns", async ({
  page,
}) => {
  const denseUsers = Array.from({ length: 10 }, (_, index) =>
    user(`u-dense-${index + 1}`, `Dense User ${index + 1}`, "baron"),
  );

  await page.route("**/api/v1/public/orgchart**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        sharedWith: "Playwright",
        tenants: [tenant("root", "Baron Group", "baron")],
        users: denseUsers,
      }),
    });
  });

  await page.goto("/chart?token=dense-members");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  const rootNode = page.locator('[data-testid="orgchart-node-root"]');
  await expect(rootNode).toHaveAttribute("width", /3\d{2}/);
  await expect(rootNode.locator('[data-member-columns="2"]')).toBeVisible();
  await expect(rootNode.getByText("Dense User 10")).toBeVisible();
});

test("public org chart hides internal and private tenants and renders org unit type", async ({
  page,
}) => {
  await page.route("**/api/v1/public/orgchart**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        sharedWith: "Playwright",
        tenants: [
          {
            ...tenant("group", "한맥가족", "hanmac-family"),
            type: "COMPANY_GROUP",
          },
          tenant("company", "삼안", "saman", "group"),
          {
            ...tenant("open-team", "공개 팀", "open-team", "company"),
            config: { orgUnitType: "팀", visibility: "public" },
          },
          {
            ...tenant("internal-team", "내부 팀", "internal-team", "company"),
            config: { visibility: "internal" },
          },
          {
            ...tenant("private-team", "비공개 팀", "private-team", "company"),
            config: { visibility: "private" },
          },
          tenant(
            "private-child",
            "비공개 하위",
            "private-child",
            "private-team",
          ),
        ],
        users: [
          user("u-open", "Open User", "open-team"),
          user("u-internal", "Internal User", "internal-team"),
          user("u-private", "Private User", "private-team"),
          user("u-private-child", "Private Child User", "private-child"),
        ],
      }),
    });
  });

  await page.goto("/chart?token=tenant-visibility");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  const svg = page.locator('[data-testid="orgchart-vector-svg"]');
  await expect(svg.getByText("공개 팀", { exact: true })).toBeVisible();
  await expect(svg.getByText("팀", { exact: true })).toBeVisible();
  await expect(svg.getByText(/Open User/)).toBeVisible();
  await expect(svg.getByText("내부 팀", { exact: true })).toHaveCount(0);
  await expect(svg.getByText("Internal User", { exact: true })).toHaveCount(0);
  await expect(svg.getByText("비공개 팀", { exact: true })).toHaveCount(0);
  await expect(svg.getByText("Private User", { exact: true })).toHaveCount(0);
  await expect(svg.getByText("비공개 하위", { exact: true })).toHaveCount(0);
  await expect(
    svg.getByText("Private Child User", { exact: true }),
  ).toHaveCount(0);
});

test("org chart colors hanmac family and nested baron company group separately", async ({
  page,
}) => {
  await page.route("**/api/v1/public/orgchart**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        sharedWith: "Playwright",
        tenants: [
          {
            ...tenant("family", "한맥가족", "hanmac-family"),
            type: "COMPANY_GROUP",
          },
          {
            ...tenant("baron-group", "Baron Group", "baron-group", "family"),
            type: "COMPANY_GROUP",
          },
          {
            ...tenant("baron-company", "Baron Company", "baron", "baron-group"),
            type: "COMPANY",
          },
        ],
        users: [user("u-baron", "Baron User", "baron")],
      }),
    });
  });

  await page.goto("/chart?token=baron-group-color");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  const svg = page.locator('[data-testid="orgchart-vector-svg"]');
  await expect(svg.getByText("Baron Group", { exact: true })).toBeVisible();

  const colors = await page.evaluate(() => {
    function headerColor(nodeId: string) {
      const node = document.querySelector(
        `[data-testid="orgchart-node-${nodeId}"]`,
      );
      const header = node?.querySelector("div > div");
      return header ? window.getComputedStyle(header).backgroundColor : "";
    }

    return {
      baronCompany: headerColor("baron-company"),
      baronGroup: headerColor("baron-group"),
      family: headerColor("family"),
    };
  });

  expect(colors.family).toBe("rgb(0, 0, 0)");
  expect(colors.baronGroup).toBe("rgb(0, 76, 191)");
  expect(colors.baronCompany).toBe("rgb(0, 76, 191)");
});

test("org chart orders top organization choices by the hanmac family policy", async ({
  page,
}) => {
  await page.route("**/api/v1/public/orgchart**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        sharedWith: "Playwright",
        tenants: [
          {
            ...tenant("family", "한맥가족", "hanmac-family"),
            type: "COMPANY_GROUP",
          },
          {
            ...tenant("saman", "삼안", "saman", "family"),
            type: "COMPANY",
          },
          {
            ...tenant("baron-group", "바론그룹", "baron-group", "family"),
            type: "COMPANY_GROUP",
          },
          {
            ...tenant("hanmac", "한맥기술", "hanmac", "family"),
            type: "COMPANY",
          },
          {
            ...tenant("gpdtdc", "총괄기획&기술개발센터", "gpdtdc", "family"),
            type: "ORGANIZATION",
          },
        ],
        users: [],
      }),
    });
  });

  await page.goto("/chart?token=org-selection-order");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  const labels = await page
    .getByTestId("orgchart-org-selector")
    .locator("button")
    .evaluateAll((buttons) =>
      buttons.map((button) => button.textContent?.trim() ?? ""),
    );

  expect(labels.slice(0, 5)).toEqual([
    "한맥가족",
    "총괄기획&기술개발센터",
    "삼안",
    "한맥기술",
    "바론그룹",
  ]);
});

test("org chart compresses many sibling organizations and allows wide zoom out", async ({
  page,
}) => {
  const childTenants = Array.from({ length: 13 }, (_, index) =>
    tenant(
      `team-${index + 1}`,
      `Team ${index + 1}`,
      `team-${index + 1}`,
      "root",
    ),
  );

  await page.route("**/api/v1/public/orgchart**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        sharedWith: "Playwright",
        tenants: [tenant("root", "Baron Group", "baron"), ...childTenants],
        users: childTenants.map((child, index) =>
          user(`u-team-${index + 1}`, `Team ${index + 1} User`, child.slug),
        ),
      }),
    });
  });

  await page.goto("/chart?token=wide-siblings");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  const viewport = page.locator('[data-testid="orgchart-viewport"]');
  const svg = page.locator('[data-testid="orgchart-vector-svg"]');
  await expect(svg).toBeVisible();
  await expect(svg.getByText("Team 13", { exact: true })).toBeVisible();
  await expect(svg.locator('foreignObject[data-node-id^="team-"]')).toHaveCount(
    13,
  );
  await expect(
    page.getByRole("button", { name: "조직: 한맥가족" }),
  ).toBeVisible();
  await expect(page.getByText("배치", { exact: true })).toBeHidden();
  await expect(page.getByRole("button", { name: "배치: 자동" })).toBeVisible();
  await expect(page.getByText("연결", { exact: true })).toHaveCount(0);
  await expect(page.getByText("상위연결", { exact: true })).toHaveCount(0);

  const autoChildYPositions = await svg
    .locator('foreignObject[data-node-id^="team-"]')
    .evaluateAll((nodes) =>
      nodes
        .map((node) => node.getAttribute("y") ?? "")
        .filter((value) => value.length > 0),
    );

  expect(new Set(autoChildYPositions).size).toBeGreaterThan(1);
  await expect(svg.locator("path")).toHaveCount(13);
  await expect(
    svg.locator('path:not([data-hidden-default="true"])'),
  ).toHaveCount(4);
  await expect(svg.locator('path[data-hidden-default="true"]')).toHaveCount(9);

  await svg.locator('foreignObject[data-node-id="team-13"]').hover();
  await expect(svg.locator('path[data-highlighted="true"]')).toHaveCount(1);
  await expect(svg.locator('path[data-muted="true"]')).toHaveCount(4);

  await page.getByTestId("orgchart-layout-mode-option").hover();
  await expect(page.getByText("배치", { exact: true })).toBeVisible();
  await expect(
    page.getByRole("button", { exact: true, name: "자동" }),
  ).toHaveCount(0);
  await page.getByRole("button", { name: "Top-down" }).click();
  await expect
    .poll(async () =>
      svg
        .locator('foreignObject[data-node-id^="team-"]')
        .evaluateAll(
          (nodes) =>
            new Set(
              nodes
                .map((node) => node.getAttribute("y") ?? "")
                .filter((value) => value.length > 0),
            ).size,
        ),
    )
    .toBe(1);

  await page.getByTestId("orgchart-layout-mode-option").hover();
  await page.getByRole("button", { name: "3열" }).click();
  const threeColumnPositions = await svg
    .locator('foreignObject[data-node-id^="team-"]')
    .evaluateAll((nodes) =>
      nodes.map((node) => ({
        x: node.getAttribute("x") ?? "",
        y: node.getAttribute("y") ?? "",
      })),
    );

  expect(new Set(threeColumnPositions.map((position) => position.x)).size).toBe(
    3,
  );
  expect(new Set(threeColumnPositions.map((position) => position.y)).size).toBe(
    5,
  );
  await expect(svg.locator("path")).toHaveCount(13);
  await expect(
    svg.locator('path:not([data-hidden-default="true"])'),
  ).toHaveCount(3);

  const box = await viewport.boundingBox();
  expect(box).not.toBeNull();
  if (!box) return;

  await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
  await page.mouse.wheel(0, 2500);

  await expect
    .poll(async () =>
      svg.evaluate((element) =>
        Number.parseFloat(element.getAttribute("data-scale") ?? "1"),
      ),
    )
    .toBeLessThan(0.45);
});

test("org chart selects first and second depth organizations from company hover choices", async ({
  page,
}) => {
  await page.route("**/api/v1/public/orgchart**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        sharedWith: "Playwright",
        tenants: [
          {
            ...tenant("group", "Baron Group", "baron"),
            type: "COMPANY_GROUP",
          },
          {
            ...tenant("company", "Company A", "company-a", "group"),
            type: "COMPANY",
          },
          tenant("department", "Department A", "department-a", "company"),
          tenant("squad", "Squad A", "squad-a", "department"),
          tenant("team", "Team A", "team-a", "squad"),
        ],
        users: [
          user("u-company", "Company User", "company-a"),
          user("u-department", "Department User", "department-a"),
          user("u-squad", "Squad User", "squad-a"),
          user("u-team", "Team User", "team-a"),
        ],
      }),
    });
  });

  await page.goto("/chart?token=company-depth-filter");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  await expect(
    page.getByRole("button", { name: "조직: 한맥가족" }),
  ).toBeVisible();
  await expect(page.getByRole("button", { name: "Company A" })).toBeVisible();
  await expect(page.getByText("하위범위", { exact: true })).toHaveCount(0);
  await expect(page.getByText("조직", { exact: true })).toHaveCount(0);
  await page.getByRole("button", { name: "Company A" }).click();
  const svg = page.locator('[data-testid="orgchart-vector-svg"]');
  await expect(svg.getByText("Team A", { exact: true })).toBeVisible();
  await expect(
    page.getByRole("button", { name: "조직: Company A" }),
  ).toBeVisible();

  await expect(
    page
      .getByTestId("orgchart-company-option-company")
      .getByRole("button", { name: "Company A" }),
  ).toBeVisible();

  const orgButtonColor = await page
    .getByRole("button", { name: "조직: Company A" })
    .evaluate((element) => window.getComputedStyle(element).backgroundColor);
  const layoutButtonColor = await page
    .getByRole("button", { name: "배치: 자동" })
    .evaluate((element) => window.getComputedStyle(element).backgroundColor);
  expect(orgButtonColor).not.toBe(layoutButtonColor);

  await page.getByTestId("orgchart-company-option-company").hover();
  await expect(svg.getByText("Department A", { exact: true })).toBeVisible();
  await page.getByRole("button", { name: "1뎁스 Department A" }).click();
  await expect(
    page.getByRole("button", { name: "조직: Department A" }),
  ).toBeVisible();
  await expect(svg.getByText("Squad A", { exact: true })).toBeVisible();

  await page.getByTestId("orgchart-company-option-company").hover();
  await page.getByRole("button", { name: "2뎁스 Squad A" }).click();
  await expect(
    page.getByRole("button", { name: "조직: Squad A" }),
  ).toBeVisible();
  await expect(svg.getByText("Squad A", { exact: true })).toBeVisible();
  await expect(svg.getByText("Team A", { exact: true })).toBeVisible();
});

test("org chart uses semantic zoom to simplify deep nodes and restore labels on zoom in", async ({
  page,
}) => {
  await page.route("**/api/v1/public/orgchart**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        sharedWith: "Playwright",
        tenants: [
          tenant("root", "Baron Group", "baron"),
          tenant("department", "Archive Department", "department", "root"),
          tenant("division", "Archive Division", "division", "department"),
          tenant("deep", "Archive Deep Team", "deep", "division"),
        ],
        users: [
          user("u-root", "Root User", "baron"),
          user("u-department", "Department User", "department"),
          user("u-division", "Division User", "division"),
          user("u-deep", "Deep User", "deep"),
        ],
      }),
    });
  });

  await page.goto("/chart?token=semantic-zoom");
  await expect(page.getByRole("heading", { name: "조직 현황" })).toBeVisible();

  const viewport = page.locator('[data-testid="orgchart-viewport"]');
  const svg = page.locator('[data-testid="orgchart-vector-svg"]');
  const deepNode = svg.locator('foreignObject[data-node-id="deep"]');

  await expect(svg).toHaveAttribute("data-semantic-zoom", "detail");
  await expect(deepNode.getByText("Archive Deep Team")).toBeVisible();

  const box = await viewport.boundingBox();
  expect(box).not.toBeNull();
  if (!box) return;

  await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
  await page.mouse.wheel(0, 4000);

  await expect
    .poll(async () => svg.getAttribute("data-semantic-zoom"))
    .toBe("overview");
  await expect(deepNode.getByText("Archive Deep Team")).toHaveCount(0);

  await page.mouse.wheel(0, -4000);

  await expect
    .poll(async () => svg.getAttribute("data-semantic-zoom"))
    .toBe("detail");
  await expect(deepNode.getByText("Archive Deep Team")).toBeVisible();
});
