// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import type { PlotLayout } from "../layout/plot-layout";

type GL = WebGL2RenderingContext | WebGLRenderingContext;

/**
 * Return CSS-pixel dimensions of the GL canvas.
 */
export function cssSize(
    gl: GL,
    dpr: number,
): { cssWidth: number; cssHeight: number } {
    return {
        cssWidth: gl.canvas.width / dpr,
        cssHeight: gl.canvas.height / dpr,
    };
}

/**
 * Clear the framebuffer + enable alpha blending. Call once per frame,
 * before any per-plot-rect {@link withScissor} invocations. Faceted
 * renderers call this once and then loop {@link withScissor} per cell
 * so the inter-facet clears don't wipe each other's pixels.
 */
export function clearAndSetupFrame(gl: GL): void {
    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
}

/**
 * Scissor-constrain `draw` to `layout.plotRect`. Caller handles
 * projection / uniforms / VBO bindings inside `draw`; this helper only
 * manages the scissor enable/disable bracket.
 *
 * Unlike {@link renderInPlotFrame}, this does *not* clear the
 * framebuffer — so it's safe to call repeatedly per frame (one per
 * facet). Pair with {@link clearAndSetupFrame} at the start of each
 * frame.
 */
export function withScissor(
    gl: GL,
    layout: PlotLayout,
    dpr: number,
    draw: () => void,
): void {
    gl.enable(gl.SCISSOR_TEST);
    gl.scissor(
        Math.round(layout.margins.left * dpr),
        Math.round(layout.margins.bottom * dpr),
        Math.round(layout.plotRect.width * dpr),
        Math.round(layout.plotRect.height * dpr),
    );
    try {
        draw();
    } finally {
        gl.disable(gl.SCISSOR_TEST);
    }
}

/**
 * One-shot convenience: clear + setup blend + scissor + draw. Used by
 * single-plot callers (bar / heatmap / candlestick / scatter-without-
 * splits) that only draw into one plot rect per frame.
 *
 * Faceted callers must use {@link clearAndSetupFrame} +
 * {@link withScissor} instead; calling this helper in a per-facet loop
 * would clear the framebuffer on each invocation and wipe out every
 * previously-drawn facet.
 */
export function renderInPlotFrame(
    gl: GL,
    layout: PlotLayout,
    dpr: number,
    draw: () => void,
): void {
    clearAndSetupFrame(gl);
    withScissor(gl, layout, dpr, draw);
}
