;(() => {
    let defer: (() => void)[] = []
    let running = false
    let paramQuality: 'standard' | 'transparent'
    let paramID: bigint

    const elemHost = document.querySelector<HTMLAnchorElement>('a.layout-wrapper')
    // @ts-expect-error
    const BASE_CDN = window.__ENV__.CDN
    // @ts-expect-error
    const BASE_WEB = window.__ENV__.WEB

    if (BASE_CDN === undefined || BASE_WEB === undefined || !elemHost) {
        console.error('[gifuu] Invalid Document')
        return
    }

    try {
        const search = new URLSearchParams(window.location.search)
        const givenQuality = search.get('quality')
        const givenID = BigInt(search.get('id') ?? '0')

        if (givenID < 1) {
            return exit('Invalid ID')
        }
        if (givenQuality !== 'standard' && givenQuality !== 'transparent') {
            return exit('Invalid Quality')
        }

        paramQuality = givenQuality
        paramID = givenID
    } catch (error) {
        exit(error)
        return
    }

    function setupGL() {
        if (!elemHost) throw 'Missing Anchor Node'

        // Setup Elements
        const elemCanvas = document.createElement('canvas')
        elemCanvas.classList.add('render')
        elemCanvas.addEventListener('webglcontextlost', (ev) => {
            ev.preventDefault()
            console.warn('[gifuu] Failed to allocate a WebGL context for us! Using image fallback...')
            teardown()
            setupImage()
        })

        elemHost.appendChild(elemCanvas)
        defer.push(() => elemCanvas.remove())

        const elemVideo = document.createElement('video')
        elemVideo.classList.add('decode')
        elemVideo.crossOrigin = 'anonymous'
        elemVideo.playsInline = true
        elemVideo.autoplay = true
        elemVideo.muted = true
        elemVideo.loop = true

        elemHost.appendChild(elemVideo)
        defer.push(() => elemVideo.remove())

        // Setup Context
        const gl = elemCanvas.getContext('webgl', {
            powerPreference: 'low-power',
            premultipliedAlpha: false,
            antialias: false,
            alpha: true,
            depth: false,
        })
        if (!gl) {
            console.warn('[gifuu] WebGL is unsupported, using image fallback...')
            teardown()
            setupImage()
            return
        }

        try {
            const VERT = `
            precision mediump float;
            attribute vec2 aPos;
            uniform mat3 uMatrix;
            varying vec2 vUV;
            void main() {
                gl_Position = vec4(uMatrix * vec3(aPos, 1.0), 1.0);
                vUV = aPos;
            }`

            const FRAG = `
            precision mediump float;
            uniform sampler2D uFrame;
            varying vec2 vUV;
            void main() {
                vec2 colorUV = vec2(vUV.x, vUV.y * 0.5);
                vec2 alphaUV = vec2(vUV.x, 0.5 + vUV.y * 0.5);
                vec4 color = texture2D(uFrame, colorUV);
                float alpha = texture2D(uFrame, alphaUV).r;
                gl_FragColor = vec4(color.rgb, alpha);
            }`

            function compileShader(type: number, src: string) {
                if (!gl) throw 'Missing GL Context'

                const s = gl.createShader(type)
                if (!s) throw 'Shader compilation failed'

                gl.shaderSource(s, src)
                gl.compileShader(s)
                return s
            }

            const prog = gl.createProgram()
            gl.attachShader(prog, compileShader(gl.VERTEX_SHADER, VERT))
            gl.attachShader(prog, compileShader(gl.FRAGMENT_SHADER, FRAG))
            gl.linkProgram(prog)
            gl.useProgram(prog)
            defer.push(() => gl.deleteProgram(prog))

            // --- Quad ---
            const buf = gl.createBuffer()
            gl.bindBuffer(gl.ARRAY_BUFFER, buf)
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1]), gl.STATIC_DRAW)
            defer.push(() => gl.deleteBuffer(buf))

            const aPos = gl.getAttribLocation(prog, 'aPos')
            gl.enableVertexAttribArray(aPos)
            gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0)
            gl.uniformMatrix3fv(gl.getUniformLocation(prog, 'uMatrix'), false, [2, 0, 0, 0, -2, 0, -1, 1, 1])

            // --- Texture ---
            const tex = gl.createTexture()
            gl.bindTexture(gl.TEXTURE_2D, tex)
            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)
            gl.uniform1i(gl.getUniformLocation(prog, 'uFrame'), 0)
            defer.push(() => gl.deleteTexture(tex))
        } catch (error) {
            console.error('[gifuu] Failed to Initialize WebGL dependencies:', error)
            teardown()
            setupImage()
            return
        }

        // Tick Function
        let cancel = 0
        let sized = false
        function tick() {
            cancel = requestAnimationFrame(tick)
            try {
                if (!gl) throw 'Missing GL Context'
                if (!sized && elemVideo.videoWidth > 0) {
                    sized = true
                    elemCanvas.width = elemVideo.videoWidth
                    elemCanvas.height = Math.floor(elemVideo.videoHeight / 2)
                    gl.viewport(0, 0, elemCanvas.width, elemCanvas.height)
                }
                if (!sized) return
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, elemVideo)
                gl.drawArrays(gl.TRIANGLES, 0, 6)
            } catch (error) {
                console.warn('[gifuu] Draw failed, using image fallback...', error)
                teardown()
                setupImage()
                return
            }
        }
        defer.push(() => cancelAnimationFrame(cancel))

        // Download Video
        fetch(`${BASE_CDN}/${paramID}/alpha.webm`, { mode: 'cors', cache: 'force-cache' })
            .then((r) => r.blob())
            .then((blob) => {
                const content = URL.createObjectURL(blob)
                defer.push(() => URL.revokeObjectURL(content))

                elemVideo.src = content
                elemVideo.play().catch(() => {})
                tick()
            })
            .catch((error) => {
                console.warn('[gifuu] Video download failed, using image fallback...', error)
                teardown()
                setupImage()
            })
    }

    function setupImage() {
        if (!elemHost) throw 'Missing Image Node'

        // Create Element
        const elemImage = document.createElement('img')
        elemImage.classList.add('render')

        elemHost.appendChild(elemImage)
        defer.push(() => elemImage.remove())

        // Download Image
        fetch(`${BASE_CDN}/${paramID}/${paramQuality}.avif`, { mode: 'cors', cache: 'force-cache' })
            .then((r) => r.blob())
            .then((blob) => {
                const content = URL.createObjectURL(blob)
                defer.push(() => URL.revokeObjectURL(content))

                elemImage.src = content
            })
            .catch((error) => {
                console.warn('[gifuu] Image download failed, quitting...', error)
                teardown()
                exit('Media Unavailable')
            })
    }

    function teardown() {
        let func
        while ((func = defer.shift())) {
            try {
                func()
            } catch (error) {
                console.error('[gifuu] Teardown failed:', error)
            }
        }
    }

    function exit(error: any) {
        console.error('[gifuu] Exiting Embed:', error)
        teardown()

        if (!elemHost) return
        elemHost.href = BASE_WEB

        const container = document.createElement('div')
        container.classList.add('error')

        const message = document.createElement('p')
        message.classList.add('message', 'effect-centered')
        message.textContent = String(error)
        container.append(message)

        elemHost.append(container)
    }

    // Lifecycle
    elemHost.href = `${BASE_WEB}/art/${paramID}`
    const observer = new IntersectionObserver(
        (entries) => {
            if (entries[0].isIntersecting && !running) {
                running = true
                console.log('[gifuu] Showtime! Setting up...')
                paramQuality === 'transparent' ? setupGL() : setupImage()
            } else if (!entries[0].isIntersecting && running) {
                running = false
                console.log('[gifuu] Out of View! Tearing down...')
                teardown()
            }
        },
        { threshold: 0.1 },
    )
    observer.observe(elemHost)

    window.addEventListener('pagehide', () => {
        console.log('[gifuu] Goodbye!')
        observer.disconnect()
        elemHost.remove()
        teardown()
    })
})()
