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 visualizer = useCallback(
        (visualizer: HTMLDivElement | null) => {
            // If we're rendering an error message, we won't be
            // setting up the visualizer.
            //
            // Also, nonintuitively, renderError will be null here on
            // subsequent iterations, so we can't rely on it to
            // identify errors.
            if (visualizer === null) {
                return;
            }

            const canvas = visualizer.children[0];
            const overlay = visualizer.children[1];

            if (
                !(canvas instanceof HTMLCanvasElement) ||
                !(overlay instanceof HTMLSpanElement)
            ) {
                throw new Error(
                    "react did not create our visualizer div correctly"
                );
            }

            const renderer = new Renderer(
                audioContext,
                audioNode,
                canvas,
                overlay
            );

            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 (
            <div
                ref={visualizer}
                className="is-flex-grow-1 is-clipped is-relative"
            >
                <canvas style={{ display: "block" }}></canvas>
                <span
                    className="is-bottom-left"
                    style={{ display: "relative" }}
                ></span>
            </div>
        );
    } else {
        return renderError;
    }
}

export default Visualizer;