import React, { useCallback, useState } from "react";
import { Renderer, RendererError } from "./Renderer";
import { ShaderError } from "./Shader";

function Visualizer({
    audioContext,
    audioNode,
}: {
    audioContext: AudioContext;
    audioNode: AudioNode;
}) {
    const [renderError, setRenderError] = useState<JSX.Element | null>(null);

    const canvas = useCallback(
        (canvas: HTMLCanvasElement | null) => {
            // If we're rendering an error message, we won't be
            // setting a canvas.
            //
            // Also, nonintuitively, renderError will be null here on
            // subsequent iterations, so we can't rely on it to
            // identify errors.
            if (canvas === null) {
                return;
            }

            const renderer = new Renderer(audioContext, audioNode, canvas);
            try {
                renderer.initializeScene();
            } catch (error) {
                // Log so we don't lose the stack trace
                console.log(error);

                if (error instanceof ShaderError) {
                    setRenderError(
                        <span>
                            Failed to compile shader; This is a bug, feel free
                            to contact me with this error message:
                            <pre>
                                <code className="has-text-danger">
                                    {error.message}
                                </code>
                            </pre>
                        </span>
                    );
                } else if (error instanceof RendererError) {
                    setRenderError(
                        <span>
                            This browser does not support WebGL 2, sadly. This
                            demo uses WebGL and specifically instanced drawing,
                            so unfortunately this means it can't run on your
                            browser/device.
                        </span>
                    );
                } else if (error instanceof Error) {
                    setRenderError(
                        <span>
                            Something went very wrong; apologies, either your
                            browser is not behaving or there's a serious bug.
                            You can contact me with this error message:
                            <pre>
                                <code className="has-text-danger">
                                    {error.message}
                                </code>
                            </pre>
                        </span>
                    );
                } else {
                    setRenderError(
                        <span>
                            Something went very wrong; apologies, either your
                            browser is not behaving or there's a serious bug.
                        </span>
                    );
                }
            }
        },
        [audioContext, audioNode]
    );

    if (renderError === null) {
        return <canvas ref={canvas} style={{ display: "block" }}></canvas>;
    } else {
        return renderError;
    }
}

export default Visualizer;
