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

const fixtures = [
  ['GLB', 'Box.glb'],
  ['Draco GLB', 'Duck.optimized.glb'],
  ['OBJ', 'Cube.obj'],
  ['FBX', 'Cube.fbx'],
  ['DAE', 'Cube.dae'],
  ['IFC', 'Cube.ifc'],
  ['double PLY', 'DoublePrecision.ply'],
] as const;

for (const [label, fixture] of fixtures) {
  test(`viewer3d renders ${label} with Three.js r185`, async ({ page }) => {
    const runtimeErrors: string[] = [];
    page.on('pageerror', (error) => runtimeErrors.push(error.message));
    page.on('console', (message) => {
      if (message.type() === 'error') runtimeErrors.push(message.text());
    });

    await page.goto(`http://127.0.0.1:3333/?model=/samples/${fixture}`);
    await page.waitForFunction(
      () =>
        Boolean(
          (
            window as Window & {
              __viewer?: { current?: object };
            }
          ).__viewer?.current,
        ),
      undefined,
      { timeout: 20_000 },
    );

    const scene = await page.evaluate(() => {
      const current = (
        window as Window & {
          __viewer?: {
            current?: {
              traverse: (visitor: (node: unknown) => void) => void;
            };
          };
        }
      ).__viewer?.current;
      let renderables = 0;
      let vertices = 0;
      let invalidValues = 0;
      let float64Attributes = 0;

      current?.traverse((node: unknown) => {
        const geometry = (
          node as {
            geometry?: {
              attributes?: {
                position?: {
                  array: ArrayLike<number>;
                  count: number;
                };
              };
            };
          }
        ).geometry;
        const position = geometry?.attributes?.position;
        if (!position) return;
        renderables += 1;
        vertices += position.count;
        if (position.array instanceof Float64Array) float64Attributes += 1;
        for (let index = 0; index < position.array.length; index += 1) {
          if (!Number.isFinite(position.array[index])) invalidValues += 1;
        }
      });

      return {
        canvases: document.querySelectorAll('canvas').length,
        float64Attributes,
        invalidValues,
        renderables,
        vertices,
      };
    });

    expect(scene.canvases).toBe(1);
    expect(scene.renderables).toBeGreaterThan(0);
    expect(scene.vertices).toBeGreaterThan(0);
    expect(scene.invalidValues).toBe(0);
    expect(scene.float64Attributes).toBe(0);
    expect(runtimeErrors).toEqual([]);
  });
}
