
async function loadFile(url) {
    const res = await fetch(url);
    return res.text();
}

function compileShader(gl, source, type) {
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        console.error('Shader compile error:', gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);
        return null;
    }
    return shader;
}

function createTexture(gl) {
    const tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    // Set parameters so we can handle non-power-of-2 images if needed
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    return tex;
}


function updateCharTexture(gl, texture, text) {
    const height = 256;
    // Dynamic width based on text length, min 1
    const chars = Math.max(1, text.length);
    const width = 256 * chars;

    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');

    ctx.clearRect(0, 0, width, height);
    ctx.fillStyle = 'white';
    ctx.font = 'bold 200px monospace';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(text, width / 2, height / 2);

    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);

    return chars; // Return aspect ratio (width/height)
}

async function main() {
    const canvas = document.getElementById('glcanvas');
    const gl = canvas.getContext('webgl');

    if (!gl) {
        alert('WebGL not supported');
        return;
    }

    // Load Shaders
    const vsSource = await loadFile('/static/shaders/vertex.glsl');
    // Using simple Cache Busting for reloading shader during dev if needed, but not strictly necessary here
    const fsSource = await loadFile('/static/shaders/fragment.glsl');

    const vs = compileShader(gl, vsSource, gl.VERTEX_SHADER);
    const fs = compileShader(gl, fsSource, gl.FRAGMENT_SHADER);

    const program = gl.createProgram();
    gl.attachShader(program, vs);
    gl.attachShader(program, fs);
    gl.linkProgram(program);

    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
        console.error('Program link error:', gl.getProgramInfoLog(program));
        return;
    }

    gl.useProgram(program);

    // Quad Buffer
    const verts = new Float32Array([
        -1, -1,
        1, -1,
        -1, 1,
        -1, 1,
        1, -1,
        1, 1,
    ]);

    const buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);

    const posLoc = gl.getAttribLocation(program, 'position');
    gl.enableVertexAttribArray(posLoc);
    gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);

    // Uniforms
    const uTime = gl.getUniformLocation(program, 'u_time');
    const uRes = gl.getUniformLocation(program, 'u_resolution');
    const uCharPos = gl.getUniformLocation(program, 'u_charPos');
    const uCharSize = gl.getUniformLocation(program, 'u_charSize');
    // Texture uniform usually defaults to 0, which is fine

    // State
    const charTexture = createTexture(gl);

    let charX = 0.5;
    let charY = 0.5;
    let charW = 0.5;
    let charH = 0.5;

    let currentAspect = 1.0;

    // UI Handling
    const input = document.getElementById('textInput');
    const btn = document.getElementById('renderBtn');

    function updateText() {
        // Use placeholder or "A" if empty to avoid 0 size
        let text = input.value.toUpperCase().substring(0, 12);
        if (text.length === 0) return;

        currentAspect = updateCharTexture(gl, charTexture, text);
        resize(); // Recalculate size
    }

    btn.addEventListener('click', updateText);

    // Initial Text
    currentAspect = updateCharTexture(gl, charTexture, "HELLO");

    function resize() {
        // Look up container size
        const container = canvas.parentElement;
        canvas.width = container.clientWidth;
        canvas.height = container.clientHeight;
        gl.viewport(0, 0, canvas.width, canvas.height);

        // Adjust aspect ratio
        const screenAspect = canvas.width / canvas.height;

        // Target: charW / charH = currentAspect / screenAspect

        // Try filling 60% of height
        charH = 0.6;
        charW = charH * currentAspect / screenAspect;

        // Constrain width to 95%
        if (charW > 0.95) {
            charW = 0.95;
            charH = charW * screenAspect / currentAspect;
        }

        charX = 0.5 - charW / 2;
        charY = 0.5 - charH / 2;
    }
    window.addEventListener('resize', resize);
    resize();

    function render(time) {
        time *= 0.001; // Seconds

        gl.uniform1f(uTime, time);
        gl.uniform2f(uRes, canvas.width, canvas.height);

        gl.uniform2f(uCharPos, charX, charY); // uniform needs bottom-left
        gl.uniform2f(uCharSize, charW, charH);

        gl.drawArrays(gl.TRIANGLES, 0, 6);
        requestAnimationFrame(render);
    }
    requestAnimationFrame(render);
}

main();
