// Camera helpers for toroidal-world (torus) mode.
//
// The renderer paints the world into a 3×3 grid of copies offset by
// `(±W, 0) × (±H, 0)` — those copies are intended to cover the
// cross-edge slack while the user pans, not to be visible all at
// once. As soon as the camera centre walks outside the central
// tile's rectangle `[0, W) × [0, H)`, the user starts seeing the
// next-tile boundary; one more world width/height of pan and they
// are at the 3×3 grid edge with empty space beyond.
//
// `wrapCameraTorus` snaps the camera back into `[0, W) × [0, H)`
// modulo the world dimensions. The toroidal world looks identical
// at `(x, y)` and `(x mod W, y mod H)`, so the snap is invisible to
// the user, while keeping the 3×3 layout enough to cover infinite
// pan in any direction.

import type { Camera, World } from "./world";

/**
 * wrapCameraTorus returns a camera whose centre is reduced modulo
 * the world dimensions so it lies within `[0, W) × [0, H)`. Camera
 * scale is preserved. Negative inputs are also handled — the result
 * is always non-negative.
 *
 * The transform is a pure mathematical no-op on the toroidal world:
 * `(centerX, centerY)` and `(centerX mod W, centerY mod H)` describe
 * the same toroidal point. Callers use the wrapped camera to keep
 * the renderer's fixed 3×3 wrap-copy layout sufficient regardless
 * of how far the user has panned.
 */
export function wrapCameraTorus(camera: Camera, world: World): Camera {
	const W = world.width;
	const H = world.height;
	return {
		centerX: positiveMod(camera.centerX, W),
		centerY: positiveMod(camera.centerY, H),
		scale: camera.scale,
	};
}

function positiveMod(value: number, modulus: number): number {
	const r = value % modulus;
	return r < 0 ? r + modulus : r;
}
