import {
    _testFinish,
    downloadBlob,
    FloatType,
    GBufferPlugin,
    HalfFloatType,
    IObject3D,
    LoadingScreenPlugin,
    RenderTargetPreviewPlugin,
    ThreeViewer,
} from 'threepipe'
import {createSimpleButtons} from '../examples-utils/simple-bottom-buttons.js'

const viewer = new ThreeViewer({
    canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
    msaa: true,
    zPrepass: true,
    plugins: [LoadingScreenPlugin],
})

async function init() {

    const gbufferPlugin = viewer.addPluginSync(new GBufferPlugin(
        HalfFloatType,
        true, // isPrimaryGBuffer (used for zprepass etc)
        true, // enabled by default
        true, // render the flags buffer (used for eg selective tonemapping)
        true, // render depth texture
        FloatType)) // render depth texture as Float type. available - UnsignedShort(16 bits), UnsignedInt(24 bits) or Float(32 bits)

    await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')
    const model = await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/kira.glb', {
        autoCenter: true,
        autoScale: true,
    })

    let id = 1
    model?.traverse((o) => {
        o.materials?.forEach(m=>{
            if (!m.userData.gBufferData) m.userData.gBufferData = {}
            if (!m.userData.gBufferData.materialId) m.userData.gBufferData.materialId = id += 10
        })
    })

    // Disable automatic near/far plane calculation based on scene bounding box
    viewer.scene.mainCamera.userData.autoNearFar = false
    viewer.scene.mainCamera.userData.minNearPlane = 1
    viewer.scene.mainCamera.userData.maxFarPlane = 10
    viewer.scene.refreshScene()

    const gbufferTarget = gbufferPlugin.target
    if (!gbufferTarget) {
        throw new Error('gbufferPlugin.target returned undefined')
    }

    // to render depth buffer to screen, uncomment this line:
    // viewer.renderManager.screenPass.overrideReadBuffer = gbufferTarget

    const getNormalDepth = ()=>({texture: gbufferPlugin.normalDepthTexture})
    const getFlags = ()=>({texture: gbufferPlugin.flagsTexture})
    const getDepthTexture = ()=>({texture: gbufferPlugin.depthTexture})

    const targetPreview = await viewer.addPlugin(RenderTargetPreviewPlugin)
    targetPreview.addTarget(getNormalDepth, 'normalDepth')
    targetPreview.addTarget(getFlags, 'gBufferFlags')
    targetPreview.addTarget(getDepthTexture, 'depthTexture')

    const screenPass = viewer.renderManager.screenPass

    createSimpleButtons({
        ['Toggle Normal+Depth']: () => {
            const rt = getNormalDepth()
            screenPass.overrideReadBuffer = screenPass.overrideReadBuffer?.texture === rt.texture ? null : rt
            viewer.setDirty()
        },
        ['Toggle Gbuffer Flags']: () => {
            const rt = getFlags()
            screenPass.overrideReadBuffer = screenPass.overrideReadBuffer?.texture === rt.texture ? null : rt
            viewer.setDirty()
        },
        ['Toggle Depth Texture']: () => {
            const rt = getDepthTexture()
            screenPass.overrideReadBuffer = screenPass.overrideReadBuffer?.texture === rt.texture ? null : rt
            viewer.setDirty()
        },
        ['Download snapshot']: async(btn: HTMLButtonElement) => {
            btn.disabled = true
            const blob = await viewer.getScreenshotBlob({mimeType: 'image/png'})
            if (blob) downloadBlob(blob, 'file.png')
            else console.error('Unable to get screenshot')
            btn.disabled = false
        },
    })

}

init().finally(_testFinish)
