/**
 *
 * @param ctx
 * @param {number} width
 * @param {number} height
 * @param {string} [color] CSS color specification
 * @param {number} spacingX distance between grid lines for x-axis
 * @param {number} spacingY distance between grid lines for y-axis
 * @param {number} offsetX
 * @param {number} offsetY
 * @param {number[]} valueRangeX
 * @param {number[]} valueRangeY
 * @param {number} thickness
 */
export function canvas2dDrawWorldGrid({
                                                   ctx,
                                                   width,
                                                   height,
                                                   color = 'red',
                                                   spacingX = 10,
                                                   spacingY = 10,
                                                   offsetX = 0,
                                                   offsetY = 0,
                                                   valueRangeX = [0,10],
                                                   valueRangeY = [0,10],
                                                   thickness = 1
                                               }) {
    ctx.fillStyle = 'none';
    ctx.lineWidth = thickness;
    ctx.strokeStyle = color;

    const [xMin, xMax] = valueRangeX;
    const [yMin, yMax] = valueRangeY;

    const plotWidth = width - offsetX * 2;
    const plotHeight = height - offsetY * 2;

    const xPixelPerUnit = plotWidth / (xMax - xMin);
    const xStepPerGrid = spacingX / xPixelPerUnit; // convert pixel spacing → world spacing

    const yPixelPerUnit = plotHeight / (yMax - yMin);
    const yStepPerGrid = spacingY / yPixelPerUnit; // convert pixel spacing → world spacing

    // find first visible grid line
    const firstX = Math.ceil(xMin / xStepPerGrid) * xStepPerGrid;
    const firstY = Math.ceil(yMin / yStepPerGrid) * yStepPerGrid;

    ctx.beginPath();

    ctx.moveTo(offsetX, 0);
    ctx.lineTo(offsetX, height);
    ctx.moveTo(0, height - offsetY);
    ctx.lineTo(width, height - offsetY);

    for (let x = firstX; x <= xMax; x += xStepPerGrid)
    {
        const xScreen = offsetX + (x - xMin) * xPixelPerUnit;
        ctx.moveTo(xScreen, 0);
        ctx.lineTo(xScreen, offsetX + plotHeight);
    }

    for (let y = firstY; y <= yMax; y += yStepPerGrid)
    {
        const yScreen = offsetY + (yMax - y) * yPixelPerUnit;
        ctx.moveTo(offsetX, yScreen);
        ctx.lineTo(width, yScreen);
    }

    ctx.stroke();
}