// Unit tests for the torus camera helper in src/map/torus.ts.
//
// `wrapCameraTorus` is the pure-math primitive the renderer uses to
// keep the camera centre inside the central tile of the 3×3 wrap
// layout. The helper guarantees three properties: the result lies
// inside `[0, W) × [0, H)`, the toroidal point is preserved (the
// transform is an additive multiple of `W` / `H`), and the camera
// scale is unchanged.

import { describe, expect, test } from "vitest";

import { World } from "../src/map/world";
import { wrapCameraTorus } from "../src/map/torus";

const world = new World(1000, 800);

describe("wrapCameraTorus", () => {
	test("leaves a camera inside [0, W) × [0, H) untouched", () => {
		const c = wrapCameraTorus(
			{ centerX: 500, centerY: 400, scale: 2 },
			world,
		);
		expect(c.centerX).toBe(500);
		expect(c.centerY).toBe(400);
		expect(c.scale).toBe(2);
	});

	test("wraps a camera one tile past the right edge back to the left", () => {
		const c = wrapCameraTorus(
			{ centerX: 1500, centerY: 200, scale: 1 },
			world,
		);
		expect(c.centerX).toBe(500);
		expect(c.centerY).toBe(200);
	});

	test("wraps a camera one tile below the top edge back to the bottom", () => {
		const c = wrapCameraTorus(
			{ centerX: 100, centerY: -300, scale: 1 },
			world,
		);
		expect(c.centerX).toBe(100);
		expect(c.centerY).toBe(500);
	});

	test("wraps a camera many tiles away on both axes", () => {
		const c = wrapCameraTorus(
			{ centerX: 1000 * 5 + 123, centerY: -800 * 7 - 45, scale: 0.5 },
			world,
		);
		expect(c.centerX).toBeCloseTo(123, 6);
		expect(c.centerY).toBeCloseTo(800 - 45, 6);
		expect(c.scale).toBe(0.5);
	});

	test("collapses the world boundary to zero (right edge wraps to left)", () => {
		const c = wrapCameraTorus(
			{ centerX: 1000, centerY: 800, scale: 1 },
			world,
		);
		// 1000 mod 1000 === 0; same for 800. The right and bottom
		// world edges map to the left and top edges.
		expect(c.centerX).toBe(0);
		expect(c.centerY).toBe(0);
	});

	test("preserves the toroidal coordinate (delta is a world-multiple)", () => {
		const before = { centerX: 1000 * 3 + 250.75, centerY: 800 * -2 + 100.25, scale: 1 };
		const after = wrapCameraTorus(before, world);
		const dx = before.centerX - after.centerX;
		const dy = before.centerY - after.centerY;
		expect(Math.abs(dx % world.width)).toBeLessThan(1e-6);
		expect(Math.abs(dy % world.height)).toBeLessThan(1e-6);
	});

	test("never returns negative coordinates", () => {
		for (const camera of [
			{ centerX: -1, centerY: -1, scale: 1 },
			{ centerX: -0.5, centerY: -0.5, scale: 1 },
			{ centerX: -world.width * 1.25, centerY: -world.height * 1.25, scale: 1 },
		]) {
			const c = wrapCameraTorus(camera, world);
			expect(c.centerX).toBeGreaterThanOrEqual(0);
			expect(c.centerX).toBeLessThan(world.width);
			expect(c.centerY).toBeGreaterThanOrEqual(0);
			expect(c.centerY).toBeLessThan(world.height);
		}
	});

	test("scale field is preserved verbatim", () => {
		const c = wrapCameraTorus(
			{ centerX: 1234, centerY: -567, scale: 0.123456 },
			world,
		);
		expect(c.scale).toBe(0.123456);
	});
});
