import { describe, it, expect, beforeAll } from 'vitest';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { createRequire } from 'node:module';

const __dirname = dirname(fileURLToPath(import.meta.url));
const require = createRequire(import.meta.url);

interface WasmModule {
  generateTestSphere(subdivisions: number): number;
  generateTestGrid(rows: number, cols: number): number;
  getVertexCount(handle: number): number;
  getFaceCount(handle: number): number;
  getVertexBuffer(handle: number): Float32Array;
  getNormalBuffer(handle: number): Float32Array;
  filterLaplacianSmooth(handle: number, iterations: number): void;
  filterSimplify(handle: number, targetFaces: number): void;
  filterSubdivide(handle: number, iterations: number): void;
  getWasmMemoryBytes(): number;
  deleteMesh(handle: number): void;
}

let core: WasmModule;

beforeAll(async () => {
  const wasmCjsPath = resolve(__dirname, '../../public/meshlab-core.cjs');
  const MeshLabCore = require(wasmCjsPath);
  core = await MeshLabCore();
}, 10000);

describe('Mesh Generation', () => {
  it('generates sphere with ~5K faces (subdiv=4)', () => {
    const h = core.generateTestSphere(4);
    const fc = core.getFaceCount(h);
    expect(fc).toBe(20 * Math.pow(4, 4)); // 5120
    core.deleteMesh(h);
  });

  it('generates sphere with ~80K faces (subdiv=6)', () => {
    const h = core.generateTestSphere(6);
    expect(core.getFaceCount(h)).toBe(20 * Math.pow(4, 6)); // 81920
    core.deleteMesh(h);
  });

  it('generates grid 100x100 = 20K faces', () => {
    const h = core.generateTestGrid(100, 100);
    expect(core.getFaceCount(h)).toBe(20000);
    core.deleteMesh(h);
  });
});

describe('Performance - Loading', () => {
  it('5K face sphere generates in < 500ms', () => {
    const start = performance.now();
    const h = core.generateTestSphere(4);
    const elapsed = performance.now() - start;
    expect(elapsed).toBeLessThan(500);
    core.deleteMesh(h);
  });

  it('80K face sphere generates in < 3s', () => {
    const start = performance.now();
    const h = core.generateTestSphere(6);
    const elapsed = performance.now() - start;
    expect(elapsed).toBeLessThan(3000);
    core.deleteMesh(h);
  });
});

describe('Performance - Filters', () => {
  it('Laplacian Smooth (5K faces, 3 iter) in < 1s', () => {
    const h = core.generateTestSphere(4);
    const start = performance.now();
    core.filterLaplacianSmooth(h, 3);
    const elapsed = performance.now() - start;
    expect(elapsed).toBeLessThan(1000);
    core.deleteMesh(h);
  });

  it('Subdivision (5K → 20K faces) in < 2s', () => {
    const h = core.generateTestSphere(4);
    const start = performance.now();
    core.filterSubdivide(h, 1);
    const elapsed = performance.now() - start;
    expect(elapsed).toBeLessThan(2000);
    expect(core.getFaceCount(h)).toBe(5120 * 4);
    core.deleteMesh(h);
  });

  it('Simplification (5K → 2.5K faces) in < 5s', () => {
    const h = core.generateTestSphere(4);
    const start = performance.now();
    core.filterSimplify(h, 2560);
    const elapsed = performance.now() - start;
    expect(elapsed).toBeLessThan(5000);
    expect(core.getFaceCount(h)).toBeLessThanOrEqual(2600);
    core.deleteMesh(h);
  });
});

describe('Memory', () => {
  it('80K face mesh keeps Wasm memory < 50MB', () => {
    const h = core.generateTestSphere(6);
    const memMB = core.getWasmMemoryBytes() / (1024 * 1024);
    expect(memMB).toBeLessThan(50);
    core.deleteMesh(h);
  });
});
