import { Plane, Point } from './Plane';
import { PlaneTransformer, PointPair } from './PlaneTransformer';
import numeric from 'numeric';

// Mock numeric if it's not available in the test environment
(global as any).numeric = numeric;

describe('PlaneTransformer', () => {
  // Test case with mobile screen and camera image
  const mobileScreen = new Plane(1080, 1920);
  const cameraImage = new Plane(640, 480);

  // Define test point pairs (these are example points that would map between the two planes)
  const pointPairs: PointPair[] = [
    { source: { x: 0, y: 0 }, target: { x: 0, y: 0 } },
    { source: { x: 1080, y: 0 }, target: { x: 640, y: 0 } },
    { source: { x: 0, y: 1920 }, target: { x: 0, y: 480 } },
    { source: { x: 1080, y: 1920 }, target: { x: 640, y: 480 } }
  ];

  let transformer: PlaneTransformer;

  beforeEach(() => {
    transformer = new PlaneTransformer(mobileScreen, cameraImage, pointPairs);
  });

  test('transforms corner points correctly', () => {
    const errorThreshold = 1e-10;

    // Test all corner points
    pointPairs.forEach(pair => {
      const transformed = transformer.transform(pair.source);
      const dx = transformed.x - pair.target.x;
      const dy = transformed.y - pair.target.y;
      const error = Math.sqrt(dx * dx + dy * dy);

      expect(error).toBeLessThan(errorThreshold);
    });
  });

  test('transforms middle point', () => {
    // Test a point in the middle of the plane
    const middleSource: Point = {
      x: mobileScreen.getWidth() / 2,
      y: mobileScreen.getHeight() / 2
    };
    const expectedTarget: Point = {
      x: cameraImage.getWidth() / 2,
      y: cameraImage.getHeight() / 2
    };

    const transformed = transformer.transform(middleSource);
    const dx = transformed.x - expectedTarget.x;
    const dy = transformed.y - expectedTarget.y;
    const error = Math.sqrt(dx * dx + dy * dy);

    expect(error).toBeLessThan(1.0); // Allow for some numerical error
  });

  test('rejects out of bounds points', () => {
    const outOfBoundsPoint: Point = {
      x: mobileScreen.getWidth() + 100,
      y: mobileScreen.getHeight() + 100
    };

    expect(() => {
      transformer.transform(outOfBoundsPoint);
    }).toThrow('Source point is out of bounds');
  });

  test('requires at least 4 point pairs', () => {
    const insufficientPoints = pointPairs.slice(0, 3);

    expect(() => {
      new PlaneTransformer(mobileScreen, cameraImage, insufficientPoints);
    }).toThrow('At least 4 point pairs are required');
  });

  test('computes reasonable transformation error', () => {
    const error = transformer.getTransformationError();
    expect(error).toBeDefined();
    expect(error).toBeGreaterThanOrEqual(0);
    expect(error).toBeLessThan(1.0); // Expect small error for perfect corner mappings
  });
}); 