import { describe, it, expect } from 'vitest';
import { arcPath, svgCoordsToViewportPx } from '../src/lib/geo.js';

describe('arcPath', () => {
  it('returns an SVG path string starting with M and containing Q', () => {
    const d = arcPath(0, 0, 100, 100);
    expect(d).toMatch(/^M 0 0 Q .+ 100 100$/);
  });

  it('control point is perpendicular to the midpoint with default curvature', () => {
    // For (0,0) → (100,0): midpoint is (50,0), dx=100, dy=0
    // cpx = 50 - 0 * 0.25 = 50, cpy = 0 + 100 * 0.25 = 25
    const d = arcPath(0, 0, 100, 0);
    expect(d).toBe('M 0 0 Q 50 25 100 0');
  });

  it('uses custom curvature', () => {
    // (0,0) → (100,0) with curvature=0.5: cpy = 50
    const d = arcPath(0, 0, 100, 0, 0.5);
    expect(d).toBe('M 0 0 Q 50 50 100 0');
  });

  it('produces a straight line when curvature is 0', () => {
    // curvature=0: control point = midpoint → effectively straight
    const d = arcPath(0, 0, 100, 100, 0);
    expect(d).toBe('M 0 0 Q 50 50 100 100');
  });

  it('handles negative coordinates', () => {
    const d = arcPath(-50, -50, 50, 50);
    expect(d).toMatch(/^M -50 -50 Q .+ 50 50$/);
  });

  it('handles same start and end point', () => {
    const d = arcPath(100, 100, 100, 100);
    expect(d).toBe('M 100 100 Q 100 100 100 100');
  });

  it('control point deflects correctly for vertical segment', () => {
    // (0,0) → (0,100): mx=0, my=50, dx=0, dy=100
    // cpx = 0 - 100 * 0.25 = -25, cpy = 50 + 0 * 0.25 = 50
    const d = arcPath(0, 0, 0, 100);
    expect(d).toBe('M 0 0 Q -25 50 0 100');
  });
});

describe('svgCoordsToViewportPx', () => {
  function makeContainer(
    width: number,
    height: number,
    left = 0,
    top = 0
  ): HTMLDivElement {
    const div = document.createElement('div');
    // Override getBoundingClientRect
    div.getBoundingClientRect = () => ({
      width,
      height,
      left,
      top,
      right: left + width,
      bottom: top + height,
      x: left,
      y: top,
      toJSON: () => ({}),
    });
    return div;
  }

  const viewBox = '0 0 1010 666';

  it('returns the container center for the SVG center point at scale=1, no offset', () => {
    const container = makeContainer(1010, 666, 0, 0);
    const transform = { x: 0, y: 0, scale: 1 };
    const { left, top } = svgCoordsToViewportPx(
      505,
      333,
      transform,
      container,
      viewBox
    );
    expect(left).toBeCloseTo(505);
    expect(top).toBeCloseTo(333);
  });

  it('maps top-left SVG corner (0,0) to container top-left at scale=1, no offset', () => {
    const container = makeContainer(1010, 666, 0, 0);
    const transform = { x: 0, y: 0, scale: 1 };
    const { left, top } = svgCoordsToViewportPx(
      0,
      0,
      transform,
      container,
      viewBox
    );
    expect(left).toBeCloseTo(0);
    expect(top).toBeCloseTo(0);
  });

  it('applies transform translation offset', () => {
    const container = makeContainer(1010, 666, 0, 0);
    const transform = { x: 100, y: 50, scale: 1 };
    const { left, top } = svgCoordsToViewportPx(
      0,
      0,
      transform,
      container,
      viewBox
    );
    // With translation: px = (0 - 505) * 1 + 505 + 100 = 100
    expect(left).toBeCloseTo(100);
    // py = (0 - 333) * 1 + 333 + 50 = 50
    expect(top).toBeCloseTo(50);
  });

  it('applies scale correctly', () => {
    const container = makeContainer(1010, 666, 0, 0);
    const transform = { x: 0, y: 0, scale: 2 };
    // SVG center (505, 333) → stays at center even when scaled around center
    const { left, top } = svgCoordsToViewportPx(
      505,
      333,
      transform,
      container,
      viewBox
    );
    expect(left).toBeCloseTo(505);
    expect(top).toBeCloseTo(333);
  });

  it('factors in container viewport offset', () => {
    const container = makeContainer(1010, 666, 200, 100);
    const transform = { x: 0, y: 0, scale: 1 };
    const { left, top } = svgCoordsToViewportPx(
      0,
      0,
      transform,
      container,
      viewBox
    );
    // px = (0 - 505) * 1 + 505 + 0 = 0 (relative to container)
    // + container left 200 = 200
    expect(left).toBeCloseTo(200);
    expect(top).toBeCloseTo(100);
  });

  it('handles custom viewBox dimensions', () => {
    const container = makeContainer(500, 500, 0, 0);
    const customViewBox = '0 0 500 500';
    const transform = { x: 0, y: 0, scale: 1 };
    // scaleX = scaleY = 1, origin = 250
    const { left, top } = svgCoordsToViewportPx(
      250,
      250,
      transform,
      container,
      customViewBox
    );
    expect(left).toBeCloseTo(250);
    expect(top).toBeCloseTo(250);
  });
});
