import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";

test("Objects menu opens controllable groups from the row and keeps plain bindings as visibility layers", async () => {
  const preview = await readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8");

  assert.match(preview, /const toggleSubjectVisibility = \(bindingId: string\)/);
  assert.match(preview, /role=\{hasControls \? "menuitem" : "menuitemcheckbox"\}/);
  assert.match(preview, /if \(hasControls\) \{\s*openSubjectWindow\(summary\.bindingId\);\s*close\(\)/);
  assert.match(preview, /toggleSubjectVisibility\(summary\.bindingId\)/);
  assert.match(preview, /visible: !state\.visible/);
  assert.match(preview, /слой скрыт · \$\{summary\.total\} объектов/);
  assert.doesNotMatch(preview, /Фильтры и счётчики: \$\{summary\.displayName\}/);
});

test("a subject window exists only when the presentation profile exposes controls", async () => {
  const preview = await readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8");

  assert.match(preview, /function hasSubjectWindowControls\(profile: MapPresentationProfile\)/);
  assert.match(preview, /if \(!state\?\.window\.open \|\| !hasSubjectWindowControls\(summary\.profile\)\) return null/);
  assert.match(preview, /window: \{ \.\.\.state\.window, open: false \}/);
});

test("hidden and visible layers have an explicit visual state", async () => {
  const styles = await readFile(new URL("../apps/catalog/src/styles.css", import.meta.url), "utf8");

  assert.match(styles, /\.catalog-map-fixture__objects-menu-item\[data-visible\]/);
  assert.match(styles, /\.catalog-map-fixture__objects-menu-item:not\(\[data-visible\]\)/);
});

test("joined detail aspects do not become independent map layers", async () => {
  const preview = await readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8");

  assert.match(preview, /dataProductBindings\.filter\(\(binding\) => !binding\.joinToBindingId\)/);
  assert.match(preview, /runtimeBindings\.filter\(\(binding\) => primaryBindingIds\.has\(binding\.bindingId\)\)/);
  assert.match(preview, /runtimeBindings=\{\[\.\.\.primaryRuntimeBindings, \.\.\.referenceRuntimeBindings\]\}/);
});

test("reference stations are first-class Objects menu layers without provider settings actions", async () => {
  const preview = await readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8");

  assert.match(preview, /const referenceObjectSummaries = useMemo/);
  assert.match(preview, /const objectLayerCount = presentationSummaries\.length \+ referenceObjectSummaries\.length/);
  assert.match(preview, /referenceObjectSummaries\.map\(\(\{ layer, displayName, total \}\)/);
  assert.match(preview, /candidate\.id === layer\.id \? \{ \.\.\.candidate, visible: !candidate\.visible \} : candidate/);
  assert.match(preview, /role="menuitemcheckbox"/);
});

test("facet window auto-fits expanded and collapsed content inside map workspace", async () => {
  const [preview, workspace] = await Promise.all([
    readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8"),
    readFile(new URL("../packages/ui-react/src/WorkspaceWindow.tsx", import.meta.url), "utf8"),
  ]);

  assert.match(preview, /minHeight=\{220\}\s*autoHeight/);
  assert.match(workspace, /autoHeight\?: boolean/);
  assert.match(workspace, /content\.scrollHeight/);
  assert.match(workspace, /availableHeight = Math\.max\(0, nextBounds\.height - normalized\.y\)/);
  assert.match(workspace, /new ResizeObserver\(scheduleFit\)/);
});

test("facet tree selection focuses the subject without resetting a compatible detail tab", async () => {
  const preview = await readFile(new URL("../apps/catalog/src/MapFixturePreview.tsx", import.meta.url), "utf8");
  const renderer = await readFile(new URL("../apps/catalog/src/CesiumMapRenderer.tsx", import.meta.url), "utf8");

  assert.match(preview, /const \[expandedFacetRows, setExpandedFacetRows\]/);
  assert.match(preview, /const handleSelectAndFocus = useCallback/);
  assert.match(preview, /mapRendererRef\.current\?\.focusRuntimeEntity\(entityId\)/);
  assert.match(preview, /setSubjectCardTabId\(\(current\) =>/);
  assert.match(preview, /profile\?\.tabs\.some\(\(tab\) => tab\.id === current\)/);
  assert.match(preview, /\(profile\?\.defaultTabId \?\? "overview"\)/);
  assert.match(renderer, /camera\.pickEllipsoid/);
  assert.match(renderer, /Cartesian3\.subtract\(camera\.position, viewportCenter/);
  assert.match(renderer, /heading: camera\.heading/);
  assert.match(renderer, /pitch: camera\.pitch/);
  assert.match(renderer, /roll: camera\.roll/);
  assert.match(renderer, /duration: 2\.1/);
});
